// xstring internal header (<string_view> without emitting non-C++17 warnings)
#pragma once
#ifndef _XSTRING_
#define _XSTRING_
#ifndef RC_INVOKED
#include <iosfwd>
#include <xmemory0>

#if _HAS_CXX17
#include <xpolymorphic_allocator.h>
#endif // _HAS_CXX17

#pragma pack(push, _CRT_PACKING)
#pragma warning(push, _STL_WARNING_LEVEL)
#pragma warning(disable : _STL_DISABLED_WARNINGS)
_STL_DISABLE_CLANG_WARNINGS
#pragma push_macro("new")
#undef new

_STD_BEGIN
// STRUCT TEMPLATE _Char_traits (FROM <string>)
template <class _Elem, class _Int_type>
struct _Char_traits { // properties of a string or stream element
    using char_type  = _Elem;
    using int_type   = _Int_type;
    using pos_type   = streampos;
    using off_type   = streamoff;
    using state_type = _Mbstatet;

    _NODISCARD static _CONSTEXPR17 int compare(_In_reads_(_Count) const _Elem* _First1,
        _In_reads_(_Count) const _Elem* _First2, size_t _Count) noexcept { // strengthened
        // compare [_First1, _First1 + _Count) with [_First2, ...)
        for (; 0 < _Count; --_Count, ++_First1, ++_First2) {
            if (*_First1 != *_First2) {
                return *_First1 < *_First2 ? -1 : +1;
            }
        }

        return 0;
    }

    _NODISCARD static _CONSTEXPR17 size_t length(_In_z_ const _Elem* _First) noexcept { // strengthened
        // find length of null-terminated sequence
        size_t _Count = 0;
        while (*_First != _Elem()) {
            ++_Count;
            ++_First;
        }

        return _Count;
    }

    static _Elem* copy(_Out_writes_all_(_Count) _Elem* const _First1, _In_reads_(_Count) const _Elem* _First2,
        size_t _Count) noexcept { // strengthened
        // copy [_First2, _First2 + _Count) to [_First1, ...)
        return static_cast<_Elem*>(_CSTD memcpy(_First1, _First2, _Count * sizeof(_Elem)));
    }

    _Pre_satisfies_(_Dest_size >= _Count) static _Elem* _Copy_s(_Out_writes_all_(_Dest_size) _Elem* const _First1,
        const size_t _Dest_size, _In_reads_(_Count) const _Elem* const _First2,
        const size_t _Count) noexcept { // copy [_First2, _First2 + _Count) to [_First1, _First1 + _Dest_size)
        _STL_VERIFY(_Count <= _Dest_size, "invalid argument");
        return copy(_First1, _First2, _Count);
    }

    _NODISCARD static _CONSTEXPR17 const _Elem* find(
        _In_reads_(_Count) const _Elem* _First, size_t _Count, const _Elem& _Ch) noexcept { // strengthened
        // look for _Ch in [_First, _First + _Count)
        for (; 0 < _Count; --_Count, ++_First) {
            if (*_First == _Ch) {
                return _First;
            }
        }

        return nullptr;
    }

    static _Elem* move(_Out_writes_all_(_Count) _Elem* const _First1, _In_reads_(_Count) const _Elem* _First2,
        size_t _Count) noexcept { // strengthened
        // copy [_First2, _First2 + _Count) to [_First1, ...), allowing overlap
        return static_cast<_Elem*>(_CSTD memmove(_First1, _First2, _Count * sizeof(_Elem)));
    }

    static _Elem* assign(
        _Out_writes_all_(_Count) _Elem* const _First, size_t _Count, const _Elem _Ch) noexcept { // strengthened
        // assign _Count * _Ch to [_First, ...)
        _Elem* _Next = _First;
        for (; 0 < _Count; --_Count, ++_Next) {
            *_Next = _Ch;
        }

        return _First;
    }

    static _CONSTEXPR17 void assign(_Elem& _Left, const _Elem& _Right) noexcept { // assign an element
        _Left = _Right;
    }

    _NODISCARD static constexpr bool eq(const _Elem& _Left, const _Elem& _Right) noexcept { // test for element equality
        return _Left == _Right;
    }

    _NODISCARD static constexpr bool lt(
        const _Elem& _Left, const _Elem& _Right) noexcept { // test if _Left precedes _Right
        return _Left < _Right;
    }

    _NODISCARD static constexpr _Elem to_char_type(
        const int_type& _Meta) noexcept { // convert metacharacter to character
        return static_cast<_Elem>(_Meta);
    }

    _NODISCARD static constexpr int_type to_int_type(const _Elem& _Ch) noexcept { // convert character to metacharacter
        return static_cast<int_type>(_Ch);
    }

    _NODISCARD static constexpr bool eq_int_type(
        const int_type& _Left, const int_type& _Right) noexcept { // test for metacharacter equality
        return _Left == _Right;
    }

    _NODISCARD static constexpr int_type not_eof(const int_type& _Meta) noexcept { // return anything but EOF
        return _Meta != eof() ? _Meta : !eof();
    }

    _NODISCARD static constexpr int_type eof() noexcept { // return end-of-file metacharacter
        return static_cast<int_type>(EOF);
    }
};

// STRUCT TEMPLATE _WChar_traits
template <class _Elem>
struct _WChar_traits { // char_traits for the char16_t-likes: char16_t, wchar_t, unsigned short
    using char_type  = _Elem;
    using int_type   = unsigned short;
    using pos_type   = streampos;
    using off_type   = streamoff;
    using state_type = _Mbstatet;

    _NODISCARD static _CONSTEXPR17 int compare(_In_reads_(_Count) const _Elem* const _First1,
        _In_reads_(_Count) const _Elem* const _First2, const size_t _Count) noexcept { // strengthened
        // compare [_First1, _First1 + _Count) with [_First2, ...)
#if _HAS_CXX17
        if constexpr (is_same_v<_Elem, wchar_t>) {
            return __builtin_wmemcmp(_First1, _First2, _Count);
        } else {
            return _Char_traits<_Elem, unsigned short>::compare(_First1, _First2, _Count);
        }
#else // _HAS_CXX17
        return _CSTD wmemcmp(
            reinterpret_cast<const wchar_t*>(_First1), reinterpret_cast<const wchar_t*>(_First2), _Count);
#endif // _HAS_CXX17
    }

    _NODISCARD static _CONSTEXPR17 size_t length(_In_z_ const _Elem* _First) noexcept { // strengthened
        // find length of null-terminated sequence
#if _HAS_CXX17
        if constexpr (is_same_v<_Elem, wchar_t>) {
            return __builtin_wcslen(_First);
        } else {
            return _Char_traits<_Elem, unsigned short>::length(_First);
        }
#else // _HAS_CXX17
        return _CSTD wcslen(reinterpret_cast<const wchar_t*>(_First));
#endif // _HAS_CXX17
    }

    static _Elem* copy(_Out_writes_all_(_Count) _Elem* const _First1, _In_reads_(_Count) const _Elem* const _First2,
        const size_t _Count) noexcept { // strengthened
        // copy [_First2, _First2 + _Count) to [_First1, ...)
        return reinterpret_cast<_Elem*>(
            _CSTD wmemcpy(reinterpret_cast<wchar_t*>(_First1), reinterpret_cast<const wchar_t*>(_First2), _Count));
    }

    _Pre_satisfies_(_Size_in_words >= _Count) static _Elem* _Copy_s(_Out_writes_all_(_Size_in_words)
                                                                        _Elem* const _First1,
        const size_t _Size_in_words, _In_reads_(_Count) const _Elem* const _First2,
        const size_t _Count) noexcept { // copy [_First2, _First2 + _Count) to [_First1, ...)
        _STL_VERIFY(_Count <= _Size_in_words, "invalid argument");
        return copy(_First1, _First2, _Count);
    }

    _NODISCARD static _CONSTEXPR17 const _Elem* find(
        _In_reads_(_Count) const _Elem* _First, const size_t _Count, const _Elem& _Ch) noexcept { // strengthened
        // look for _Ch in [_First, _First + _Count)
#if _HAS_CXX17
        if constexpr (is_same_v<_Elem, wchar_t>) {
            return __builtin_wmemchr(_First, _Ch, _Count);
        } else {
            return _Char_traits<_Elem, unsigned short>::find(_First, _Count, _Ch);
        }
#else // _HAS_CXX17
        return reinterpret_cast<const _Elem*>(_CSTD wmemchr(reinterpret_cast<const wchar_t*>(_First), _Ch, _Count));
#endif // _HAS_CXX17
    }

    static _Elem* move(_Out_writes_all_(_Count) _Elem* const _First1, _In_reads_(_Count) const _Elem* const _First2,
        const size_t _Count) noexcept { // strengthened
        // copy [_First2, _First2 + _Count) to [_First1, ...)
        return reinterpret_cast<_Elem*>(
            _CSTD wmemmove(reinterpret_cast<wchar_t*>(_First1), reinterpret_cast<const wchar_t*>(_First2), _Count));
    }

    static _Elem* assign(
        _Out_writes_all_(_Count) _Elem* const _First, size_t _Count, _Elem _Ch) noexcept { // strengthened
        // assign _Count * _Ch to [_First, ...)
        return reinterpret_cast<_Elem*>(_CSTD wmemset(reinterpret_cast<wchar_t*>(_First), _Ch, _Count));
    }

    static _CONSTEXPR17 void assign(_Elem& _Left, const _Elem& _Right) noexcept { // assign an element
        _Left = _Right;
    }

    _NODISCARD static constexpr bool eq(const _Elem& _Left, const _Elem& _Right) noexcept { // test for element equality
        return _Left == _Right;
    }

    _NODISCARD static constexpr bool lt(
        const _Elem& _Left, const _Elem& _Right) noexcept { // test if _Left precedes _Right
        return _Left < _Right;
    }

    _NODISCARD static constexpr _Elem to_char_type(
        const int_type& _Meta) noexcept { // convert metacharacter to character
        return _Meta;
    }

    _NODISCARD static constexpr int_type to_int_type(const _Elem& _Ch) noexcept { // convert character to metacharacter
        return _Ch;
    }

    _NODISCARD static constexpr bool eq_int_type(
        const int_type& _Left, const int_type& _Right) noexcept { // test for metacharacter equality
        return _Left == _Right;
    }

    _NODISCARD static constexpr int_type not_eof(const int_type& _Meta) noexcept { // return anything but EOF
        return _Meta != eof() ? _Meta : static_cast<int_type>(!eof());
    }

    _NODISCARD static constexpr int_type eof() noexcept { // return end-of-file metacharacter
        return WEOF;
    }
};

// STRUCT TEMPLATE char_traits
template <class _Elem>
struct char_traits : _Char_traits<_Elem, long> { // properties of a string or stream unknown element
};

// STRUCT char_traits<char16_t>
template <>
struct char_traits<char16_t> : _WChar_traits<char16_t> { // properties of a string or stream char16_t element
};

using u16streampos = streampos;

// STRUCT char_traits<char32_t>
template <>
struct char_traits<char32_t>
    : _Char_traits<char32_t, unsigned int> { // properties of a string or stream char32_t element
};

using u32streampos = streampos;

// STRUCT char_traits<wchar_t>
template <>
struct char_traits<wchar_t> : _WChar_traits<wchar_t> { // properties of a string or stream wchar_t element
};

#ifdef _NATIVE_WCHAR_T_DEFINED
// STRUCT char_traits<unsigned short>
template <>
struct char_traits<unsigned short>
    : _WChar_traits<unsigned short> { // properties of a string or stream unsigned short element
};
#endif // _NATIVE_WCHAR_T_DEFINED

// STRUCT char_traits<char> (FROM <string>)
template <>
struct char_traits<char> { // properties of a string or stream char element
    using char_type  = char;
    using int_type   = int;
    using pos_type   = streampos;
    using off_type   = streamoff;
    using state_type = _Mbstatet;

    _NODISCARD static _CONSTEXPR17 int compare(_In_reads_(_Count) const char* const _First1,
        _In_reads_(_Count) const char* const _First2, const size_t _Count) noexcept { // strengthened
        // compare [_First1, _First1 + _Count) with [_First2, ...)
#if _HAS_CXX17
        return __builtin_memcmp(_First1, _First2, _Count);
#else // _HAS_CXX17
        return _CSTD memcmp(_First1, _First2, _Count);
#endif // _HAS_CXX17
    }

    _NODISCARD static _CONSTEXPR17 size_t length(_In_z_ const char* const _First) noexcept { // strengthened
        // find length of null-terminated string
#if _HAS_CXX17
        return __builtin_strlen(_First);
#else // _HAS_CXX17
        return _CSTD strlen(_First);
#endif // _HAS_CXX17
    }

    static char* copy(_Out_writes_(_Count) char* const _First1, _In_reads_(_Count) const char* const _First2,
        const size_t _Count) noexcept { // strengthened
        // copy [_First2, _First2 + _Count) to [_First1, ...)
        return static_cast<char*>(_CSTD memcpy(_First1, _First2, _Count));
    }

    _Pre_satisfies_(_Size_in_bytes >= _Count) static char* _Copy_s(_Out_writes_all_(_Size_in_bytes) char* const _First1,
        const size_t _Size_in_bytes, _In_reads_(_Count) const char* const _First2,
        const size_t _Count) noexcept { // copy [_First2, _First2 + _Count) to [_First1, ...)
        _STL_VERIFY(_Count <= _Size_in_bytes, "invalid argument");
        return copy(_First1, _First2, _Count);
    }

    _NODISCARD static _CONSTEXPR17 const char* find(
        _In_reads_(_Count) const char* const _First, const size_t _Count, const char& _Ch) noexcept { // strengthened
        // look for _Ch in [_First, _First + _Count)
#if _HAS_CXX17
        return __builtin_char_memchr(_First, _Ch, _Count);
#else // _HAS_CXX17
        return static_cast<const char*>(_CSTD memchr(_First, _Ch, _Count));
#endif // _HAS_CXX17
    }

    static char* move(_Out_writes_all_(_Count) char* const _First1, _In_reads_(_Count) const char* const _First2,
        const size_t _Count) noexcept { // strengthened
        // copy [_First2, _First2 + _Count) to [_First1, ...)
        return static_cast<char*>(_CSTD memmove(_First1, _First2, _Count));
    }

    static char* assign(
        _Out_writes_all_(_Count) char* const _First, const size_t _Count, const char _Ch) noexcept { // strengthened
        // assign _Count * _Ch to [_First, ...)
        return static_cast<char*>(_CSTD memset(_First, _Ch, _Count));
    }

    static _CONSTEXPR17 void assign(char& _Left, const char& _Right) noexcept { // assign an element
        _Left = _Right;
    }

    _NODISCARD static constexpr bool eq(const char& _Left, const char& _Right) noexcept { // test for element equality
        return _Left == _Right;
    }

    _NODISCARD static constexpr bool lt(
        const char& _Left, const char& _Right) noexcept { // test if _Left precedes _Right
        return static_cast<unsigned char>(_Left) < static_cast<unsigned char>(_Right);
    }

    _NODISCARD static constexpr char to_char_type(
        const int_type& _Meta) noexcept { // convert metacharacter to character
        return static_cast<char>(_Meta);
    }

    _NODISCARD static constexpr int_type to_int_type(const char& _Ch) noexcept { // convert character to metacharacter
        return static_cast<unsigned char>(_Ch);
    }

    _NODISCARD static constexpr bool eq_int_type(
        const int_type& _Left, const int_type& _Right) noexcept { // test for metacharacter equality
        return _Left == _Right;
    }

    _NODISCARD static constexpr int_type not_eof(const int_type& _Meta) noexcept { // return anything but EOF
        return _Meta != eof() ? _Meta : !eof();
    }

    _NODISCARD static constexpr int_type eof() noexcept { // return end-of-file metacharacter
        return EOF;
    }
};

template <class _Elem, class _Traits, class _SizeT>
inline basic_ostream<_Elem, _Traits>& _Insert_string(basic_ostream<_Elem, _Traits>& _Ostr, const _Elem* const _Data,
    const _SizeT _Size) { // insert a character-type sequence into _Ostr as if through a basic_string copy
    using _Ostr_t                    = basic_ostream<_Elem, _Traits>;
    typename _Ostr_t::iostate _State = _Ostr_t::goodbit;
    _SizeT _Pad                      = _Ostr.width() <= 0 || static_cast<_SizeT>(_Ostr.width()) <= _Size
                      ? 0
                      : static_cast<_SizeT>(_Ostr.width()) - _Size;
    const typename _Ostr_t::sentry _Ok(_Ostr);

    if (!_Ok) {
        _State |= _Ostr_t::badbit;
    } else { // state okay, insert characters
        _TRY_IO_BEGIN
        if ((_Ostr.flags() & _Ostr_t::adjustfield) != _Ostr_t::left) {
            for (; 0 < _Pad; --_Pad) { // pad on left
                if (_Traits::eq_int_type(_Traits::eof(), _Ostr.rdbuf()->sputc(_Ostr.fill()))) {
                    _State |= _Ostr_t::badbit; // insertion failed, quit
                    break;
                }
            }
        }

        if (_State == _Ostr_t::goodbit && _Ostr.rdbuf()->sputn(_Data, (streamsize) _Size) != (streamsize) _Size) {
            _State |= _Ostr_t::badbit;
        } else {
            for (; 0 < _Pad; --_Pad) { // pad on right
                if (_Traits::eq_int_type(_Traits::eof(), _Ostr.rdbuf()->sputc(_Ostr.fill()))) {
                    _State |= _Ostr_t::badbit; // insertion failed, quit
                    break;
                }
            }
        }

        _Ostr.width(0);
        _CATCH_IO_(_Ostr_t, _Ostr)
    }

    _Ostr.setstate(_State);
    return _Ostr;
}

// STRUCT TEMPLATE _Char_traits_eq
template <class _Traits>
struct _Char_traits_eq {
    using _Elem = typename _Traits::char_type;

    bool operator()(_Elem _Left, _Elem _Right) const {
        return _Traits::eq(_Left, _Right);
    }
};

// STRUCT TEMPLATE _Char_traits_lt
template <class _Traits>
struct _Char_traits_lt {
    using _Elem = typename _Traits::char_type;

    bool operator()(_Elem _Left, _Elem _Right) const {
        return _Traits::lt(_Left, _Right);
    }
};

template <class _Elem>
struct _Equal_memcmp_is_safe_helper<_Elem, _Elem, _Char_traits_eq<char_traits<_Elem>>>
    : _Equal_memcmp_is_safe_helper<_Elem, _Elem, equal_to<>>::type { // builtin char_traits::eq behaves like equal_to<>
};

template <class _Traits>
using _Traits_ch_t = typename _Traits::char_type;

template <class _Traits>
using _Traits_ptr_t = const typename _Traits::char_type*;

template <class _Traits>
constexpr bool _Traits_equal(_In_reads_(_Left_size) const _Traits_ptr_t<_Traits> _Left, const size_t _Left_size,
    _In_reads_(_Right_size) const _Traits_ptr_t<_Traits> _Right,
    const size_t _Right_size) noexcept { // compare [_Left, _Left + _Left_size) to [_Right, _Right + _Right_size) for
                                         // equality using _Traits
    return _Left_size == _Right_size && _Traits::compare(_Left, _Right, _Left_size) == 0;
}

template <class _Traits>
constexpr int _Traits_compare(_In_reads_(_Left_size) const _Traits_ptr_t<_Traits> _Left, const size_t _Left_size,
    _In_reads_(_Right_size) const _Traits_ptr_t<_Traits> _Right,
    const size_t
        _Right_size) noexcept { // compare [_Left, _Left + _Left_size) to [_Right, _Right + _Right_size) using _Traits
    const int _Ans = _Traits::compare(_Left, _Right, _Min_value(_Left_size, _Right_size));

    if (_Ans != 0) {
        return _Ans;
    }

    if (_Left_size < _Right_size) {
        return -1;
    }

    if (_Left_size > _Right_size) {
        return 1;
    }

    return 0;
}

template <class _Traits>
constexpr size_t _Traits_find(_In_reads_(_Hay_size) const _Traits_ptr_t<_Traits> _Haystack, const size_t _Hay_size,
    const size_t _Start_at, _In_reads_(_Needle_size) const _Traits_ptr_t<_Traits> _Needle,
    const size_t _Needle_size) noexcept { // search [_Haystack, _Haystack + _Hay_size) for [_Needle, _Needle +
                                          // _Needle_size), at/after _Start_at
    if (_Needle_size > _Hay_size
        || _Start_at > _Hay_size - _Needle_size) { // xpos cannot exist, report failure
                                                   // N4659 24.3.2.7.2 [string.find]/1 says:
                                                   // 1. _Start_at <= xpos
                                                   // 2. xpos + _Needle_size <= _Hay_size;
                                                   // therefore:
                                                   // 3. _Needle_size <= _Hay_size (by 2) (checked above)
                                                   // 4. _Start_at + _Needle_size <= _Hay_size (substitute 1 into 2)
                                                   // 5. _Start_at <= _Hay_size - _Needle_size (4, move _Needle_size to
                                                   // other side) (also checked above)
        return static_cast<size_t>(-1);
    }

    if (_Needle_size == 0) { // empty string always matches if xpos is possible
        return _Start_at;
    }

    const auto _Possible_matches_end = _Haystack + (_Hay_size - _Needle_size) + 1;
    for (auto _Match_try = _Haystack + _Start_at;; ++_Match_try) {
        _Match_try = _Traits::find(_Match_try, static_cast<size_t>(_Possible_matches_end - _Match_try), *_Needle);
        if (!_Match_try) { // didn't find first character; report failure
            return static_cast<size_t>(-1);
        }

        if (_Traits::compare(_Match_try, _Needle, _Needle_size) == 0) { // found match
            return static_cast<size_t>(_Match_try - _Haystack);
        }
    }
}

template <class _Traits>
constexpr size_t _Traits_find_ch(_In_reads_(_Hay_size) const _Traits_ptr_t<_Traits> _Haystack, const size_t _Hay_size,
    const size_t _Start_at,
    const _Traits_ch_t<_Traits> _Ch) noexcept { // search [_Haystack, _Haystack + _Hay_size) for _Ch, at/after _Start_at
    if (_Start_at < _Hay_size) {
        const auto _Found_at = _Traits::find(_Haystack + _Start_at, _Hay_size - _Start_at, _Ch);
        if (_Found_at) {
            return static_cast<size_t>(_Found_at - _Haystack);
        }
    }

    return static_cast<size_t>(-1); // (npos) no match
}

template <class _Traits>
constexpr size_t _Traits_rfind(_In_reads_(_Hay_size) const _Traits_ptr_t<_Traits> _Haystack, const size_t _Hay_size,
    const size_t _Start_at, _In_reads_(_Needle_size) const _Traits_ptr_t<_Traits> _Needle,
    const size_t _Needle_size) noexcept { // search [_Haystack, _Haystack + _Hay_size) for [_Needle, _Needle +
                                          // _Needle_size) beginning before _Start_at
    if (_Needle_size == 0) {
        return _Min_value(_Start_at, _Hay_size); // empty string always matches
    }

    if (_Needle_size <= _Hay_size) { // room for match, look for it
        for (auto _Match_try = _Haystack + _Min_value(_Start_at, _Hay_size - _Needle_size);; --_Match_try) {
            if (_Traits::eq(*_Match_try, *_Needle) && _Traits::compare(_Match_try, _Needle, _Needle_size) == 0) {
                return static_cast<size_t>(_Match_try - _Haystack); // found a match
            }

            if (_Match_try == _Haystack) {
                break; // at beginning, no more chance for match
            }
        }
    }

    return static_cast<size_t>(-1); // no match
}

template <class _Traits>
constexpr size_t _Traits_rfind_ch(_In_reads_(_Hay_size) const _Traits_ptr_t<_Traits> _Haystack, const size_t _Hay_size,
    const size_t _Start_at,
    const _Traits_ch_t<_Traits> _Ch) noexcept { // search [_Haystack, _Haystack + _Hay_size) for _Ch before _Start_at
    if (_Hay_size != 0) { // room for match, look for it
        for (auto _Match_try = _Haystack + _Min_value(_Start_at, _Hay_size - 1);; --_Match_try) {
            if (_Traits::eq(*_Match_try, _Ch)) {
                return static_cast<size_t>(_Match_try - _Haystack); // found a match
            }

            if (_Match_try == _Haystack) {
                break; // at beginning, no more chance for match
            }
        }
    }

    return static_cast<size_t>(-1); // no match
}

template <class _Elem,
    bool = _Is_character<_Elem>::value>
class _String_bitmap { // _String_bitmap for character types
public:
    constexpr bool _Mark(const _Elem* _First,
        const _Elem* const _Last) { // mark this bitmap such that the characters in [_First, _Last) are intended to
                                    // match returns whether all inputs can be placed in the bitmap
        for (; _First != _Last; ++_First) {
            _Matches[static_cast<unsigned char>(*_First)] = true;
        }

        return true;
    }

    constexpr bool _Match(const _Elem _Ch) const { // test if _Ch is in the bitmap
        return _Matches[static_cast<unsigned char>(_Ch)];
    }

private:
    bool _Matches[256] = {};
};

template <class _Elem>
class _String_bitmap<_Elem, false> { // _String_bitmap for wchar_t/unsigned short/char16_t/char32_t/etc. types
public:
    static_assert(is_unsigned_v<_Elem>,
        "Standard char_traits is only provided for char, wchar_t, char16_t, and char32_t. See N5687 [char.traits]. "
        "Visual C++ accepts other unsigned integral types as an extension.");

    constexpr bool _Mark(const _Elem* _First,
        const _Elem* const _Last) { // mark this bitmap such that the characters in [_First, _Last) are intended to
                                    // match returns whether all inputs can be placed in the bitmap
        for (; _First != _Last; ++_First) {
            const auto _Ch = *_First;
            if (_Ch >= 256U) {
                return false;
            }

            _Matches[static_cast<unsigned char>(_Ch)] = true;
        }

        return true;
    }

    constexpr bool _Match(const _Elem _Ch) const { // test if _Ch is in the bitmap
        return _Ch < 256U && _Matches[_Ch];
    }

private:
    bool _Matches[256] = {};
};

template <class _Traits>
constexpr size_t _Traits_find_first_of(_In_reads_(_Hay_size) const _Traits_ptr_t<_Traits> _Haystack,
    const size_t _Hay_size, const size_t _Start_at, _In_reads_(_Needle_size) const _Traits_ptr_t<_Traits> _Needle,
    const size_t _Needle_size,
    false_type) noexcept { // in [_Haystack, _Haystack + _Hay_size), look for one of [_Needle, _Needle + _Needle_size),
                           // at/after _Start_at general algorithm
    if (_Needle_size != 0 && _Start_at < _Hay_size) { // room for match, look for it
        const auto _End = _Haystack + _Hay_size;
        for (auto _Match_try = _Haystack + _Start_at; _Match_try < _End; ++_Match_try) {
            if (_Traits::find(_Needle, _Needle_size, *_Match_try)) {
                return static_cast<size_t>(_Match_try - _Haystack); // found a match
            }
        }
    }

    return static_cast<size_t>(-1); // no match
}

template <class _Traits>
constexpr size_t _Traits_find_first_of(_In_reads_(_Hay_size) const _Traits_ptr_t<_Traits> _Haystack,
    const size_t _Hay_size, const size_t _Start_at, _In_reads_(_Needle_size) const _Traits_ptr_t<_Traits> _Needle,
    const size_t _Needle_size,
    true_type) noexcept { // in [_Haystack, _Haystack + _Hay_size), look for one of [_Needle, _Needle + _Needle_size),
                          // at/after _Start_at special case for std::char_traits
    if (_Needle_size != 0 && _Start_at < _Hay_size) { // room for match, look for it
        _String_bitmap<typename _Traits::char_type> _Matches;
        if (!_Matches._Mark(_Needle, _Needle + _Needle_size)) { // couldn't put one of the characters into the bitmap,
                                                                // fall back to the serial algorithm
            return _Traits_find_first_of<_Traits>(_Haystack, _Hay_size, _Start_at, _Needle, _Needle_size, false_type{});
        }

        const auto _End = _Haystack + _Hay_size;
        for (auto _Match_try = _Haystack + _Start_at; _Match_try < _End; ++_Match_try) {
            if (_Matches._Match(*_Match_try)) {
                return static_cast<size_t>(_Match_try - _Haystack); // found a match
            }
        }
    }

    return static_cast<size_t>(-1); // no match
}

template <class _Traits>
constexpr size_t _Traits_find_last_of(_In_reads_(_Hay_size) const _Traits_ptr_t<_Traits> _Haystack,
    const size_t _Hay_size, const size_t _Start_at, _In_reads_(_Needle_size) const _Traits_ptr_t<_Traits> _Needle,
    const size_t _Needle_size,
    false_type) noexcept { // in [_Haystack, _Haystack + _Hay_size), look for last of [_Needle, _Needle + _Needle_size),
                           // before _Start_at general algorithm
    if (_Needle_size != 0 && _Hay_size != 0) { // worth searching, do it
        for (auto _Match_try = _Haystack + _Min_value(_Start_at, _Hay_size - 1);; --_Match_try) {
            if (_Traits::find(_Needle, _Needle_size, *_Match_try)) {
                return static_cast<size_t>(_Match_try - _Haystack); // found a match
            }

            if (_Match_try == _Haystack) {
                break; // at beginning, no more chance for match
            }
        }
    }

    return static_cast<size_t>(-1); // no match
}

template <class _Traits>
constexpr size_t _Traits_find_last_of(_In_reads_(_Hay_size) const _Traits_ptr_t<_Traits> _Haystack,
    const size_t _Hay_size, const size_t _Start_at, _In_reads_(_Needle_size) const _Traits_ptr_t<_Traits> _Needle,
    const size_t _Needle_size,
    true_type) noexcept { // in [_Haystack, _Haystack + _Hay_size), look for last of [_Needle, _Needle + _Needle_size),
                          // before _Start_at special case for std::char_traits
    if (_Needle_size != 0 && _Hay_size != 0) { // worth searching, do it
        _String_bitmap<typename _Traits::char_type> _Matches;
        if (!_Matches._Mark(_Needle, _Needle + _Needle_size)) { // couldn't put one of the characters into the bitmap,
                                                                // fall back to the serial algorithm
            return _Traits_find_last_of<_Traits>(_Haystack, _Hay_size, _Start_at, _Needle, _Needle_size, false_type{});
        }

        for (auto _Match_try = _Haystack + _Min_value(_Start_at, _Hay_size - 1);; --_Match_try) {
            if (_Matches._Match(*_Match_try)) {
                return static_cast<size_t>(_Match_try - _Haystack); // found a match
            }

            if (_Match_try == _Haystack) {
                break; // at beginning, no more chance for match
            }
        }
    }

    return static_cast<size_t>(-1); // no match
}

template <class _Traits>
constexpr size_t _Traits_find_first_not_of(_In_reads_(_Hay_size) const _Traits_ptr_t<_Traits> _Haystack,
    const size_t _Hay_size, const size_t _Start_at, _In_reads_(_Needle_size) const _Traits_ptr_t<_Traits> _Needle,
    const size_t _Needle_size,
    false_type) noexcept { // in [_Haystack, _Haystack + _Hay_size), look for none of [_Needle, _Needle + _Needle_size),
                           // at/after _Start_at general algorithm
    if (_Start_at < _Hay_size) { // room for match, look for it
        const auto _End = _Haystack + _Hay_size;
        for (auto _Match_try = _Haystack + _Start_at; _Match_try < _End; ++_Match_try) {
            if (!_Traits::find(_Needle, _Needle_size, *_Match_try)) {
                return static_cast<size_t>(_Match_try - _Haystack); // found a match
            }
        }
    }

    return static_cast<size_t>(-1); // no match
}

template <class _Traits>
constexpr size_t _Traits_find_first_not_of(_In_reads_(_Hay_size) const _Traits_ptr_t<_Traits> _Haystack,
    const size_t _Hay_size, const size_t _Start_at, _In_reads_(_Needle_size) const _Traits_ptr_t<_Traits> _Needle,
    const size_t _Needle_size,
    true_type) noexcept { // in [_Haystack, _Haystack + _Hay_size), look for none of [_Needle, _Needle + _Needle_size),
                          // at/after _Start_at special case for std::char_traits
    if (_Start_at < _Hay_size) { // room for match, look for it
        _String_bitmap<typename _Traits::char_type> _Matches;
        if (!_Matches._Mark(_Needle, _Needle + _Needle_size)) { // couldn't put one of the characters into the bitmap,
                                                                // fall back to the serial algorithm
            return _Traits_find_first_not_of<_Traits>(
                _Haystack, _Hay_size, _Start_at, _Needle, _Needle_size, false_type{});
        }

        const auto _End = _Haystack + _Hay_size;
        for (auto _Match_try = _Haystack + _Start_at; _Match_try < _End; ++_Match_try) {
            if (!_Matches._Match(*_Match_try)) {
                return static_cast<size_t>(_Match_try - _Haystack); // found a match
            }
        }
    }

    return static_cast<size_t>(-1); // no match
}

template <class _Traits>
constexpr size_t _Traits_find_not_ch(_In_reads_(_Hay_size) const _Traits_ptr_t<_Traits> _Haystack,
    const size_t _Hay_size, const size_t _Start_at,
    const _Traits_ch_t<_Traits>
        _Ch) noexcept { // search [_Haystack, _Haystack + _Hay_size) for any value other than _Ch, at/after _Start_at
    if (_Start_at < _Hay_size) { // room for match, look for it
        const auto _End = _Haystack + _Hay_size;
        for (auto _Match_try = _Haystack + _Start_at; _Match_try < _End; ++_Match_try) {
            if (!_Traits::eq(*_Match_try, _Ch)) {
                return static_cast<size_t>(_Match_try - _Haystack); // found a match
            }
        }
    }

    return static_cast<size_t>(-1); // no match
}

template <class _Traits>
constexpr size_t _Traits_find_last_not_of(_In_reads_(_Hay_size) const _Traits_ptr_t<_Traits> _Haystack,
    const size_t _Hay_size, const size_t _Start_at, _In_reads_(_Needle_size) const _Traits_ptr_t<_Traits> _Needle,
    const size_t _Needle_size,
    false_type) noexcept { // in [_Haystack, _Haystack + _Hay_size), look for none of [_Needle, _Needle + _Needle_size),
                           // before _Start_at general algorithm
    if (_Hay_size != 0) { // worth searching, do it
        for (auto _Match_try = _Haystack + _Min_value(_Start_at, _Hay_size - 1);; --_Match_try) {
            if (!_Traits::find(_Needle, _Needle_size, *_Match_try)) {
                return static_cast<size_t>(_Match_try - _Haystack); // found a match
            }

            if (_Match_try == _Haystack) {
                break; // at beginning, no more chance for match
            }
        }
    }

    return static_cast<size_t>(-1); // no match
}

template <class _Traits>
constexpr size_t _Traits_find_last_not_of(_In_reads_(_Hay_size) const _Traits_ptr_t<_Traits> _Haystack,
    const size_t _Hay_size, const size_t _Start_at, _In_reads_(_Needle_size) const _Traits_ptr_t<_Traits> _Needle,
    const size_t _Needle_size,
    true_type) noexcept { // in [_Haystack, _Haystack + _Hay_size), look for none of [_Needle, _Needle + _Needle_size),
                          // before _Start_at special case for std::char_traits
    if (_Hay_size != 0) { // worth searching, do it
        _String_bitmap<typename _Traits::char_type> _Matches;
        if (!_Matches._Mark(_Needle, _Needle + _Needle_size)) { // couldn't put one of the characters into the bitmap,
                                                                // fall back to the serial algorithm
            return _Traits_find_last_not_of<_Traits>(
                _Haystack, _Hay_size, _Start_at, _Needle, _Needle_size, false_type{});
        }

        for (auto _Match_try = _Haystack + _Min_value(_Start_at, _Hay_size - 1);; --_Match_try) {
            if (!_Matches._Match(*_Match_try)) {
                return static_cast<size_t>(_Match_try - _Haystack); // found a match
            }

            if (_Match_try == _Haystack) {
                break; // at beginning, no more chance for match
            }
        }
    }

    return static_cast<size_t>(-1); // no match
}

template <class _Traits>
constexpr size_t _Traits_rfind_not_ch(_In_reads_(_Hay_size) const _Traits_ptr_t<_Traits> _Haystack,
    const size_t _Hay_size, const size_t _Start_at,
    const _Traits_ch_t<_Traits>
        _Ch) noexcept { // search [_Haystack, _Haystack + _Hay_size) for any value other than _Ch before _Start_at
    if (_Hay_size != 0) { // room for match, look for it
        for (auto _Match_try = _Haystack + _Min_value(_Start_at, _Hay_size - 1);; --_Match_try) {
            if (!_Traits::eq(*_Match_try, _Ch)) {
                return static_cast<size_t>(_Match_try - _Haystack); // found a match
            }

            if (_Match_try == _Haystack) {
                break; // at beginning, no more chance for match
            }
        }
    }

    return static_cast<size_t>(-1); // no match
}


#if _HAS_CXX17
// CLASS TEMPLATE _String_view_iterator
template <class _Elem, class _Traits = char_traits<_Elem>>
class basic_string_view;

template <class _Traits>
class _String_view_iterator { // iterator for character buffer wrapper
public:
    using iterator_category = random_access_iterator_tag;
    using value_type        = typename _Traits::char_type;
    using difference_type   = ptrdiff_t;
    using pointer           = const value_type*;
    using reference         = const value_type&;

    constexpr _String_view_iterator() noexcept
#if _ITERATOR_DEBUG_LEVEL >= 1
        : _Mydata(), _Mysize(0), _Myoff(0)
#else // ^^^ _ITERATOR_DEBUG_LEVEL >= 1 ^^^ // vvv _ITERATOR_DEBUG_LEVEL == 0 vvv
        : _Myptr()
#endif // _ITERATOR_DEBUG_LEVEL
    { // default-initialize a basic_string_view::const_iterator
    }

private:
    friend basic_string_view<value_type, _Traits>;

#if _ITERATOR_DEBUG_LEVEL >= 1
    constexpr _String_view_iterator(const pointer _Data, const size_t _Size, const size_t _Off) noexcept
        : _Mydata(_Data), _Mysize(_Size), _Myoff(_Off) { // initialize a basic_string_view::const_iterator
    }
#else // ^^^ _ITERATOR_DEBUG_LEVEL >= 1 ^^^ // vvv _ITERATOR_DEBUG_LEVEL == 0 vvv
    constexpr explicit _String_view_iterator(const pointer _Ptr) noexcept
        : _Myptr(_Ptr) { // initialize a basic_string_view::const_iterator
    }
#endif // _ITERATOR_DEBUG_LEVEL

public:
    _NODISCARD constexpr reference operator*() const noexcept { // return designated object
#if _ITERATOR_DEBUG_LEVEL >= 1
        _STL_VERIFY(_Mydata, "cannot dereference value-initialized string_view iterator");
        _STL_VERIFY(_Myoff < _Mysize, "cannot dereference end string_view iterator");
        return _Mydata[_Myoff];
#else // ^^^ _ITERATOR_DEBUG_LEVEL >= 1 ^^^ // vvv _ITERATOR_DEBUG_LEVEL == 0 vvv
        return *_Myptr;
#endif // _ITERATOR_DEBUG_LEVEL
    }

    _NODISCARD constexpr pointer operator->() const noexcept { // return pointer to class object
#if _ITERATOR_DEBUG_LEVEL >= 1
        _STL_VERIFY(_Mydata, "cannot dereference value-initialized string_view iterator");
        _STL_VERIFY(_Myoff < _Mysize, "cannot dereference end string_view iterator");
        return _Mydata + _Myoff;
#else // ^^^ _ITERATOR_DEBUG_LEVEL >= 1 ^^^ // vvv _ITERATOR_DEBUG_LEVEL == 0 vvv
        return _Myptr;
#endif // _ITERATOR_DEBUG_LEVEL
    }

    constexpr _String_view_iterator& operator++() noexcept { // preincrement
#if _ITERATOR_DEBUG_LEVEL >= 1
        _STL_VERIFY(_Mydata, "cannot increment value-initialized string_view iterator");
        _STL_VERIFY(_Myoff < _Mysize, "cannot increment string_view iterator past end");
        ++_Myoff;
#else // ^^^ _ITERATOR_DEBUG_LEVEL >= 1 ^^^ // vvv _ITERATOR_DEBUG_LEVEL == 0 vvv
        ++_Myptr;
#endif // _ITERATOR_DEBUG_LEVEL
        return *this;
    }

    constexpr _String_view_iterator operator++(int) noexcept { // postincrement
        _String_view_iterator _Tmp{*this};
        ++*this;
        return _Tmp;
    }

    constexpr _String_view_iterator& operator--() noexcept { // predecrement
#if _ITERATOR_DEBUG_LEVEL >= 1
        _STL_VERIFY(_Mydata, "cannot decrement value-initialized string_view iterator");
        _STL_VERIFY(_Myoff != 0, "cannot decrement string_view iterator before begin");
        --_Myoff;
#else // ^^^ _ITERATOR_DEBUG_LEVEL >= 1 ^^^ // vvv _ITERATOR_DEBUG_LEVEL == 0 vvv
        --_Myptr;
#endif // _ITERATOR_DEBUG_LEVEL
        return *this;
    }

    constexpr _String_view_iterator operator--(int) noexcept { // postdecrement
        _String_view_iterator _Tmp{*this};
        --*this;
        return _Tmp;
    }

    constexpr void _Verify_offset(const difference_type _Off) const noexcept {
#if _ITERATOR_DEBUG_LEVEL >= 1
        if (_Off != 0) {
            _STL_VERIFY(_Mydata, "cannot seek value-initialized string_view iterator");
        }

        if (_Off < 0) {
#pragma warning(suppress : 4146) // unary minus operator applied to unsigned type, result still unsigned
            _STL_VERIFY(_Myoff >= -static_cast<size_t>(_Off), "cannot seek string_view iterator before begin");
        }

        if (_Off > 0) {
            _STL_VERIFY(_Mysize - _Myoff >= static_cast<size_t>(_Off), "cannot seek string_view iterator after end");
        }
#else // ^^^ _ITERATOR_DEBUG_LEVEL >= 1 ^^^ // vvv _ITERATOR_DEBUG_LEVEL == 0 vvv
        (void) _Off;
#endif // _ITERATOR_DEBUG_LEVEL >= 1
    }

    constexpr _String_view_iterator& operator+=(const difference_type _Off) noexcept { // increment by integer
#if _ITERATOR_DEBUG_LEVEL >= 1
        _Verify_offset(_Off);
        _Myoff += _Off;
#else // ^^^ _ITERATOR_DEBUG_LEVEL >= 1 ^^^ // vvv _ITERATOR_DEBUG_LEVEL == 0 vvv
        _Myptr += _Off;
#endif // _ITERATOR_DEBUG_LEVEL

        return *this;
    }

    _NODISCARD constexpr _String_view_iterator operator+(const difference_type _Off) const
        noexcept { // return this + integer
        _String_view_iterator _Tmp{*this};
        _Tmp += _Off;
        return _Tmp;
    }

    constexpr _String_view_iterator& operator-=(const difference_type _Off) noexcept { // decrement by integer
#if _ITERATOR_DEBUG_LEVEL >= 1
        if (_Off != 0) {
            _STL_VERIFY(_Mydata, "cannot seek value-initialized string_view iterator");
        }

        if (_Off > 0) {
            _STL_VERIFY(_Myoff >= static_cast<size_t>(_Off), "cannot seek string_view iterator before begin");
        }

        if (_Off < 0) {
#pragma warning(suppress : 4146) // unary minus operator applied to unsigned type, result still unsigned
            _STL_VERIFY(_Mysize - _Myoff >= -static_cast<size_t>(_Off), "cannot seek string_view iterator after end");
        }

        _Myoff -= _Off;
#else // ^^^ _ITERATOR_DEBUG_LEVEL >= 1 ^^^ // vvv _ITERATOR_DEBUG_LEVEL == 0 vvv
        _Myptr -= _Off;
#endif // _ITERATOR_DEBUG_LEVEL

        return *this;
    }

    _NODISCARD constexpr _String_view_iterator operator-(const difference_type _Off) const
        noexcept { // return this - integer
        _String_view_iterator _Tmp{*this};
        _Tmp -= _Off;
        return _Tmp;
    }

    _NODISCARD constexpr difference_type operator-(const _String_view_iterator& _Right) const
        noexcept { // return difference of iterators
#if _ITERATOR_DEBUG_LEVEL >= 1
        _STL_VERIFY(_Mydata == _Right._Mydata && _Mysize == _Right._Mysize,
            "cannot subtract incompatible string_view iterators");
        return static_cast<difference_type>(_Myoff - _Right._Myoff);
#else // ^^^ _ITERATOR_DEBUG_LEVEL >= 1 ^^^ // vvv _ITERATOR_DEBUG_LEVEL == 0 vvv
        return _Myptr - _Right._Myptr;
#endif // _ITERATOR_DEBUG_LEVEL
    }

    _NODISCARD constexpr reference operator[](const difference_type _Off) const noexcept { // subscript
        return *(*this + _Off);
    }

    _NODISCARD constexpr bool operator==(const _String_view_iterator& _Right) const
        noexcept { // test for iterator equality
#if _ITERATOR_DEBUG_LEVEL >= 1
        _STL_VERIFY(_Mydata == _Right._Mydata && _Mysize == _Right._Mysize,
            "cannot compare incompatible string_view iterators for equality");
        return _Myoff == _Right._Myoff;
#else // ^^^ _ITERATOR_DEBUG_LEVEL >= 1 ^^^ // vvv _ITERATOR_DEBUG_LEVEL == 0 vvv
        return _Myptr == _Right._Myptr;
#endif // _ITERATOR_DEBUG_LEVEL
    }

    _NODISCARD constexpr bool operator!=(const _String_view_iterator& _Right) const
        noexcept { // test for iterator inequality
        return !(*this == _Right);
    }

    _NODISCARD constexpr bool operator<(const _String_view_iterator& _Right) const noexcept { // test if this < _Right
#if _ITERATOR_DEBUG_LEVEL >= 1
        _STL_VERIFY(_Mydata == _Right._Mydata && _Mysize == _Right._Mysize,
            "cannot compare incompatible string_view iterators");
        return _Myoff < _Right._Myoff;
#else // ^^^ _ITERATOR_DEBUG_LEVEL >= 1 ^^^ // vvv _ITERATOR_DEBUG_LEVEL == 0 vvv
        return _Myptr < _Right._Myptr;
#endif // _ITERATOR_DEBUG_LEVEL
    }

    _NODISCARD constexpr bool operator>(const _String_view_iterator& _Right) const noexcept { // test if this > _Right
        return _Right < *this;
    }

    _NODISCARD constexpr bool operator<=(const _String_view_iterator& _Right) const noexcept { // test if this <= _Right
        return !(_Right < *this);
    }

    _NODISCARD constexpr bool operator>=(const _String_view_iterator& _Right) const noexcept { // test if this >= _Right
        return !(*this < _Right);
    }

#if _ITERATOR_DEBUG_LEVEL >= 1
    friend constexpr void _Verify_range(const _String_view_iterator& _First, const _String_view_iterator& _Last) {
        _STL_VERIFY(_First._Mydata == _Last._Mydata && _First._Mysize == _Last._Mysize,
            "string_view iterators in range are from different views");
        _STL_VERIFY(_First._Myoff <= _Last._Myoff, "string_view iterator range transposed");
    }
#endif // _ITERATOR_DEBUG_LEVEL >= 1

    using _Prevent_inheriting_unwrap = _String_view_iterator;

    _NODISCARD constexpr pointer _Unwrapped() const noexcept {
#if _ITERATOR_DEBUG_LEVEL >= 1
        return _Mydata + _Myoff;
#else // ^^^ _ITERATOR_DEBUG_LEVEL >= 1 ^^^ // vvv _ITERATOR_DEBUG_LEVEL == 0 vvv
        return _Myptr;
#endif // _ITERATOR_DEBUG_LEVEL
    }

    static constexpr bool _Unwrap_when_unverified = _ITERATOR_DEBUG_LEVEL == 0;

    constexpr void _Seek_to(pointer _It) noexcept {
#if _ITERATOR_DEBUG_LEVEL >= 1
        _Myoff = static_cast<size_t>(_It - _Mydata);
#else // ^^^ _ITERATOR_DEBUG_LEVEL >= 1 ^^^ // vvv _ITERATOR_DEBUG_LEVEL == 0 vvv
        _Myptr = _It;
#endif // _ITERATOR_DEBUG_LEVEL
    }

private:
#if _ITERATOR_DEBUG_LEVEL >= 1
    pointer _Mydata;
    size_t _Mysize;
    size_t _Myoff;
#else // ^^^ _ITERATOR_DEBUG_LEVEL >= 1 ^^^ // vvv _ITERATOR_DEBUG_LEVEL == 0 vvv
    pointer _Myptr;
#endif // _ITERATOR_DEBUG_LEVEL
};

template <class _Traits>
_NODISCARD constexpr _String_view_iterator<_Traits> operator+(
    const typename _String_view_iterator<_Traits>::difference_type _Off,
    _String_view_iterator<_Traits> _Right) noexcept { // return integer + _Right
    _Right += _Off;
    return _Right;
}


// CLASS TEMPLATE basic_string_view
template <class _Elem, class _Traits>
class basic_string_view { // wrapper for any kind of contiguous character buffer
public:
    static_assert(is_same_v<_Elem, typename _Traits::char_type>,
        "Bad char_traits for basic_string_view; "
        "N4659 24.4.2 [string.view.template]/1 \"the type traits::char_type shall name the same type as charT.\"");

    using traits_type            = _Traits;
    using value_type             = _Elem;
    using pointer                = _Elem*;
    using const_pointer          = const _Elem*;
    using reference              = _Elem&;
    using const_reference        = const _Elem&;
    using const_iterator         = _String_view_iterator<_Traits>;
    using iterator               = const_iterator;
    using const_reverse_iterator = _STD reverse_iterator<const_iterator>;
    using reverse_iterator       = const_reverse_iterator;
    using size_type              = size_t;
    using difference_type        = ptrdiff_t;

    static constexpr auto npos{static_cast<size_type>(-1)};

    constexpr basic_string_view() noexcept : _Mydata(), _Mysize(0) { // construct empty basic_string_view
    }

    constexpr basic_string_view(const basic_string_view&) noexcept = default;
    constexpr basic_string_view& operator=(const basic_string_view&) noexcept = default;

    /* implicit */ constexpr basic_string_view(_In_z_ const const_pointer _Ntcts) noexcept // strengthened
        : _Mydata(_Ntcts),
          _Mysize(
              _Traits::length(_Ntcts)) { // construct basic_string_view around a null-terminated character-type sequence
    }

    constexpr basic_string_view(
        _In_reads_(_Count) const const_pointer _Cts, const size_type _Count) noexcept // strengthened
        : _Mydata(_Cts),
          _Mysize(_Count) { // construct basic_string_view around a character-type sequence with explicit size
#if _ITERATOR_DEBUG_LEVEL >= 1
        _STL_VERIFY(_Count == 0 || _Cts, "non-zero size null string_view");
#endif // _ITERATOR_DEBUG_LEVEL >= 1
    }

    _NODISCARD constexpr const_iterator begin() const noexcept { // get the beginning of the range
#if _ITERATOR_DEBUG_LEVEL >= 1
        return const_iterator(_Mydata, _Mysize, 0);
#else // ^^^ _ITERATOR_DEBUG_LEVEL >= 1 ^^^ // vvv _ITERATOR_DEBUG_LEVEL == 0 vvv
        return const_iterator(_Mydata);
#endif // _ITERATOR_DEBUG_LEVEL
    }

    _NODISCARD constexpr const_iterator end() const noexcept { // get the end of the range
#if _ITERATOR_DEBUG_LEVEL >= 1
        return const_iterator(_Mydata, _Mysize, _Mysize);
#else // ^^^ _ITERATOR_DEBUG_LEVEL >= 1 ^^^ // vvv _ITERATOR_DEBUG_LEVEL == 0 vvv
        return const_iterator(_Mydata + _Mysize);
#endif // _ITERATOR_DEBUG_LEVEL
    }

    _NODISCARD constexpr const_iterator cbegin() const noexcept { // get the beginning of the range
        return begin();
    }

    _NODISCARD constexpr const_iterator cend() const noexcept { // get the end of the range
        return end();
    }

    _NODISCARD constexpr const_reverse_iterator rbegin() const noexcept { // get the beginning of the reversed range
        return const_reverse_iterator{end()};
    }

    _NODISCARD constexpr const_reverse_iterator rend() const noexcept { // get the end of the reversed range
        return const_reverse_iterator{begin()};
    }

    _NODISCARD constexpr const_reverse_iterator crbegin() const noexcept { // get the beginning of the reversed range
        return rbegin();
    }

    _NODISCARD constexpr const_reverse_iterator crend() const noexcept { // get the end of the reversed range
        return rend();
    }

    constexpr const_pointer _Unchecked_begin() const noexcept { // get pointer to beginning of the range
        return _Mydata;
    }

    constexpr const_pointer _Unchecked_end() const noexcept { // get pointer to end of the range
        return _Mydata + _Mysize;
    }

    _NODISCARD constexpr size_type size() const noexcept { // get the size of this basic_string_view
        return _Mysize;
    }

    _NODISCARD constexpr size_type length() const noexcept { // get the size of this basic_string_view
        return _Mysize;
    }

    _NODISCARD constexpr bool empty() const noexcept { // check whether this basic_string_view is empty
        return _Mysize == 0;
    }

    _NODISCARD constexpr const_pointer data() const noexcept { // get the base pointer of this basic_string_view
        return _Mydata;
    }

    _NODISCARD constexpr size_type max_size() const
        noexcept { // get the maximum possible size
                   // bound to PTRDIFF_MAX to make end() - begin() well defined (also makes room for npos)
                   // bound to static_cast<size_t>(-1) / sizeof(_Elem) by address space limits
        return _Min_value(static_cast<size_t>(PTRDIFF_MAX), static_cast<size_t>(-1) / sizeof(_Elem));
    }

    _NODISCARD constexpr const_reference operator[](const size_type _Off) const noexcept { // strengthened
        // get character at offset; assume offset is in range
#if _ITERATOR_DEBUG_LEVEL >= 1
        _STL_VERIFY(_Off < _Mysize, "string_view subscript out of range");
#endif // _ITERATOR_DEBUG_LEVEL >= 1
        return _Mydata[_Off];
    }

    _NODISCARD constexpr const_reference at(
        const size_type _Off) const { // get the character at _Off or throw if that is out of range
        _Check_offset_exclusive(_Off);
        return _Mydata[_Off];
    }

    _NODISCARD constexpr const_reference front() const noexcept { // strengthened
        // returns a reference to the first character in *this
#if _ITERATOR_DEBUG_LEVEL >= 1
        _STL_VERIFY(_Mysize != 0, "cannot call front on empty string_view");
#endif // _ITERATOR_DEBUG_LEVEL >= 1
        return _Mydata[0];
    }

    _NODISCARD constexpr const_reference back() const noexcept { // strengthened
        // returns a reference to the last character in *this
#if _ITERATOR_DEBUG_LEVEL >= 1
        _STL_VERIFY(_Mysize != 0, "cannot call back on empty string_view");
#endif // _ITERATOR_DEBUG_LEVEL >= 1
        return _Mydata[_Mysize - 1];
    }

    constexpr void remove_prefix(const size_type _Count) noexcept { // strengthened
        // chop off the beginning
#if _ITERATOR_DEBUG_LEVEL >= 1
        _STL_VERIFY(_Mysize >= _Count, "cannot remove prefix longer than total size");
#endif // _ITERATOR_DEBUG_LEVEL >= 1
        _Mydata += _Count;
        _Mysize -= _Count;
    }

    constexpr void remove_suffix(const size_type _Count) noexcept { // strengthened
        // chop off the end
#if _ITERATOR_DEBUG_LEVEL >= 1
        _STL_VERIFY(_Mysize >= _Count, "cannot remove suffix longer than total size");
#endif // _ITERATOR_DEBUG_LEVEL >= 1
        _Mysize -= _Count;
    }

    constexpr void swap(basic_string_view& _Other) noexcept { // swap contents
        const basic_string_view _Tmp{_Other}; // note: std::swap is not constexpr
        _Other = *this;
        *this  = _Tmp;
    }

    constexpr size_type copy(_Out_writes_(_Count) _Elem* const _Ptr, size_type _Count,
        const size_type _Off = 0) const { // copy [_Off, _Off + Count) to [_Ptr, _Ptr + _Count)
        _Check_offset(_Off);
        _Count = _Clamp_suffix_size(_Off, _Count);
        _Traits::copy(_Ptr, _Mydata + _Off, _Count);
        return _Count;
    }

    _Pre_satisfies_(_Dest_size >= _Count) constexpr size_type
        _Copy_s(_Out_writes_all_(_Dest_size) _Elem* const _Dest, const size_type _Dest_size, size_type _Count,
            const size_type _Off = 0) const { // copy [_Off, _Off + _Count) to [_Dest, _Dest + _Count)
        _Check_offset(_Off);
        _Count = _Clamp_suffix_size(_Off, _Count);
        _Traits::_Copy_s(_Dest, _Dest_size, _Mydata + _Off, _Count);
        return _Count;
    }

    _NODISCARD constexpr basic_string_view substr(const size_type _Off = 0, size_type _Count = npos)
        const { // return a new basic_string_view moved forward by _Off and trimmed to _Count elements
        _Check_offset(_Off);
        _Count = _Clamp_suffix_size(_Off, _Count);
        return basic_string_view(_Mydata + _Off, _Count);
    }

    constexpr bool _Equal(const basic_string_view _Right) const noexcept { // test if *this and _Right are equal
        return _Traits_equal<_Traits>(_Mydata, _Mysize, _Right._Mydata, _Right._Mysize);
    }

    _NODISCARD constexpr int compare(const basic_string_view _Right) const
        noexcept { // compare [0, _Mysize) with _Right
        return _Traits_compare<_Traits>(_Mydata, _Mysize, _Right._Mydata, _Right._Mysize);
    }

    _NODISCARD constexpr int compare(const size_type _Off, const size_type _N0,
        const basic_string_view _Right) const { // compare [_Off, _Off + _N0) with _Right
        return substr(_Off, _N0).compare(_Right);
    }

    _NODISCARD constexpr int compare(const size_type _Off, const size_type _N0, const basic_string_view _Right,
        const size_type _Roff,
        const size_type _Count) const { // compare [_Off, _Off + _N0) with _Right [_Roff, _Roff + _Count)
        return substr(_Off, _N0).compare(_Right.substr(_Roff, _Count));
    }

    _NODISCARD constexpr int compare(_In_z_ const _Elem* const _Ptr) const { // compare [0, _Mysize) with [_Ptr, <null>)
        return compare(basic_string_view(_Ptr));
    }

    _NODISCARD constexpr int compare(const size_type _Off, const size_type _N0,
        _In_z_ const _Elem* const _Ptr) const { // compare [_Off, _Off + _N0) with [_Ptr, <null>)
        return substr(_Off, _N0).compare(basic_string_view(_Ptr));
    }

    _NODISCARD constexpr int compare(const size_type _Off, const size_type _N0,
        _In_reads_(_Count) const _Elem* const _Ptr,
        const size_type _Count) const { // compare [_Off, _Off + _N0) with [_Ptr, _Ptr + _Count)
        return substr(_Off, _N0).compare(basic_string_view(_Ptr, _Count));
    }

#if _HAS_CXX20
    _NODISCARD constexpr bool starts_with(const basic_string_view _Right) const noexcept {
        // test if this instance starts with _Right
        const auto _Rightsize = _Right._Mysize;
        if (_Mysize < _Rightsize) {
            return false;
        }
        return _Traits::compare(_Mydata, _Right._Mydata, _Rightsize) == 0;
    }

    _NODISCARD constexpr bool starts_with(const _Elem _Right) const noexcept {
        // test if this instance starts with _Right
        return !empty() && _Traits::eq(front(), _Right);
    }

    _NODISCARD constexpr bool starts_with(const _Elem* const _Right) const noexcept { // strengthened
        // test if this instance starts with _Right
        return starts_with(basic_string_view(_Right));
    }

    _NODISCARD constexpr bool ends_with(const basic_string_view _Right) const noexcept {
        // test if this instance ends with _Right
        const auto _Rightsize = _Right._Mysize;
        if (_Mysize < _Rightsize) {
            return false;
        }
        return _Traits::compare(_Mydata + (_Mysize - _Rightsize), _Right._Mydata, _Rightsize) == 0;
    }

    _NODISCARD constexpr bool ends_with(const _Elem _Right) const noexcept {
        // test if this instance ends with _Right
        return !empty() && _Traits::eq(back(), _Right);
    }

    _NODISCARD constexpr bool ends_with(const _Elem* const _Right) const noexcept { // strengthened
        // test if this instance ends with _Right
        return ends_with(basic_string_view(_Right));
    }
#endif // _HAS_CXX20

    _NODISCARD constexpr size_type find(const basic_string_view _Right, const size_type _Off = 0) const
        noexcept { // look for _Right beginning at or after _Off
        return _Traits_find<_Traits>(_Mydata, _Mysize, _Off, _Right._Mydata, _Right._Mysize);
    }

    _NODISCARD constexpr size_type find(const _Elem _Ch, const size_type _Off = 0) const
        noexcept { // look for _Ch at or after _Off
        return _Traits_find_ch<_Traits>(_Mydata, _Mysize, _Off, _Ch);
    }

    _NODISCARD constexpr size_type find(_In_reads_(_Count) const _Elem* const _Ptr, const size_type _Off,
        const size_type _Count) const noexcept { // strengthened
        // look for [_Ptr, _Ptr + _Count) beginning at or after _Off
        return _Traits_find<_Traits>(_Mydata, _Mysize, _Off, _Ptr, _Count);
    }

    _NODISCARD constexpr size_type find(_In_z_ const _Elem* const _Ptr, const size_type _Off = 0) const
        noexcept { // strengthened
        // look for [_Ptr, <null>) beginning at or after _Off
        return _Traits_find<_Traits>(_Mydata, _Mysize, _Off, _Ptr, _Traits::length(_Ptr));
    }

    _NODISCARD constexpr size_type rfind(const basic_string_view _Right, const size_type _Off = npos) const
        noexcept { // look for _Right beginning before _Off
        return _Traits_rfind<_Traits>(_Mydata, _Mysize, _Off, _Right._Mydata, _Right._Mysize);
    }

    _NODISCARD constexpr size_type rfind(const _Elem _Ch, const size_type _Off = npos) const
        noexcept { // look for _Ch before _Off
        return _Traits_rfind_ch<_Traits>(_Mydata, _Mysize, _Off, _Ch);
    }

    _NODISCARD constexpr size_type rfind(_In_reads_(_Count) const _Elem* const _Ptr, const size_type _Off,
        const size_type _Count) const noexcept { // strengthened
        // look for [_Ptr, _Ptr + _Count) beginning before _Off
        return _Traits_rfind<_Traits>(_Mydata, _Mysize, _Off, _Ptr, _Count);
    }

    _NODISCARD constexpr size_type rfind(_In_z_ const _Elem* const _Ptr, const size_type _Off = npos) const
        noexcept { // strengthened
        // look for [_Ptr, <null>) beginning before _Off
        return _Traits_rfind<_Traits>(_Mydata, _Mysize, _Off, _Ptr, _Traits::length(_Ptr));
    }

    _NODISCARD constexpr size_type find_first_of(const basic_string_view _Right,
        const size_type _Off = 0) const noexcept { // look for one of _Right at or after _Off
        return _Traits_find_first_of<_Traits>(
            _Mydata, _Mysize, _Off, _Right._Mydata, _Right._Mysize, _Is_specialization<_Traits, char_traits>{});
    }

    _NODISCARD constexpr size_type find_first_of(const _Elem _Ch, const size_type _Off = 0) const
        noexcept { // look for _Ch at or after _Off
        return _Traits_find_ch<_Traits>(_Mydata, _Mysize, _Off, _Ch);
    }

    _NODISCARD constexpr size_type find_first_of(_In_reads_(_Count) const _Elem* const _Ptr, const size_type _Off,
        const size_type _Count) const noexcept { // strengthened
        // look for one of [_Ptr, _Ptr + _Count) at or after _Off
        return _Traits_find_first_of<_Traits>(
            _Mydata, _Mysize, _Off, _Ptr, _Count, _Is_specialization<_Traits, char_traits>{});
    }

    _NODISCARD constexpr size_type find_first_of(_In_z_ const _Elem* const _Ptr,
        const size_type _Off = 0) const noexcept { // strengthened
        // look for one of [_Ptr, <null>) at or after _Off
        return _Traits_find_first_of<_Traits>(
            _Mydata, _Mysize, _Off, _Ptr, _Traits::length(_Ptr), _Is_specialization<_Traits, char_traits>{});
    }

    _NODISCARD constexpr size_type find_last_of(const basic_string_view _Right, const size_type _Off = npos) const
        noexcept { // look for one of _Right before _Off
        return _Traits_find_last_of<_Traits>(
            _Mydata, _Mysize, _Off, _Right._Mydata, _Right._Mysize, _Is_specialization<_Traits, char_traits>{});
    }

    _NODISCARD constexpr size_type find_last_of(const _Elem _Ch, const size_type _Off = npos) const
        noexcept { // look for _Ch before _Off
        return _Traits_rfind_ch<_Traits>(_Mydata, _Mysize, _Off, _Ch);
    }

    _NODISCARD constexpr size_type find_last_of(_In_reads_(_Count) const _Elem* const _Ptr, const size_type _Off,
        const size_type _Count) const noexcept { // strengthened
        // look for one of [_Ptr, _Ptr + _Count) before _Off
        return _Traits_find_last_of<_Traits>(
            _Mydata, _Mysize, _Off, _Ptr, _Count, _Is_specialization<_Traits, char_traits>{});
    }

    _NODISCARD constexpr size_type find_last_of(_In_z_ const _Elem* const _Ptr, const size_type _Off = npos) const
        noexcept { // strengthened
        // look for one of [_Ptr, <null>) before _Off
        return _Traits_find_last_of<_Traits>(
            _Mydata, _Mysize, _Off, _Ptr, _Traits::length(_Ptr), _Is_specialization<_Traits, char_traits>{});
    }

    _NODISCARD constexpr size_type find_first_not_of(const basic_string_view _Right,
        const size_type _Off = 0) const noexcept { // look for none of _Right at or after _Off
        return _Traits_find_first_not_of<_Traits>(
            _Mydata, _Mysize, _Off, _Right._Mydata, _Right._Mysize, _Is_specialization<_Traits, char_traits>{});
    }

    _NODISCARD constexpr size_type find_first_not_of(const _Elem _Ch, const size_type _Off = 0) const
        noexcept { // look for any value other than _Ch at or after _Off
        return _Traits_find_not_ch<_Traits>(_Mydata, _Mysize, _Off, _Ch);
    }

    _NODISCARD constexpr size_type find_first_not_of(_In_reads_(_Count) const _Elem* const _Ptr, const size_type _Off,
        const size_type _Count) const noexcept { // strengthened
        // look for none of [_Ptr, _Ptr + _Count) at or after _Off
        return _Traits_find_first_not_of<_Traits>(
            _Mydata, _Mysize, _Off, _Ptr, _Count, _Is_specialization<_Traits, char_traits>{});
    }

    _NODISCARD constexpr size_type find_first_not_of(_In_z_ const _Elem* const _Ptr, const size_type _Off = 0) const
        noexcept { // strengthened
        // look for none of [_Ptr, <null>) at or after _Off
        return _Traits_find_first_not_of<_Traits>(
            _Mydata, _Mysize, _Off, _Ptr, _Traits::length(_Ptr), _Is_specialization<_Traits, char_traits>{});
    }

    _NODISCARD constexpr size_type find_last_not_of(const basic_string_view _Right,
        const size_type _Off = npos) const noexcept { // look for none of _Right before _Off
        return _Traits_find_last_not_of<_Traits>(
            _Mydata, _Mysize, _Off, _Right._Mydata, _Right._Mysize, _Is_specialization<_Traits, char_traits>{});
    }

    _NODISCARD constexpr size_type find_last_not_of(const _Elem _Ch, const size_type _Off = npos) const
        noexcept { // look for any value other than _Ch before _Off
        return _Traits_rfind_not_ch<_Traits>(_Mydata, _Mysize, _Off, _Ch);
    }

    _NODISCARD constexpr size_type find_last_not_of(_In_reads_(_Count) const _Elem* const _Ptr, const size_type _Off,
        const size_type _Count) const noexcept { // strengthened
        // look for none of [_Ptr, _Ptr + _Count) before _Off
        return _Traits_find_last_not_of<_Traits>(
            _Mydata, _Mysize, _Off, _Ptr, _Count, _Is_specialization<_Traits, char_traits>{});
    }

    _NODISCARD constexpr size_type find_last_not_of(_In_z_ const _Elem* const _Ptr, const size_type _Off = npos) const
        noexcept { // strengthened
        // look for none of [_Ptr, <null>) before _Off
        return _Traits_find_last_not_of<_Traits>(
            _Mydata, _Mysize, _Off, _Ptr, _Traits::length(_Ptr), _Is_specialization<_Traits, char_traits>{});
    }

    _NODISCARD constexpr bool _Starts_with(const basic_string_view _View) const
        noexcept { // test if this instance begins with _View
        return _Mysize >= _View._Mysize && _Traits::compare(_Mydata, _View._Mydata, _View._Mysize) == 0;
    }

private:
    constexpr void _Check_offset(const size_type _Off) const { // checks whether _Off is in the bounds of [0, size()]
        if (_Mysize < _Off) {
            _Xran();
        }
    }

    constexpr void _Check_offset_exclusive(
        const size_type _Off) const { // checks whether _Off is in the bounds of [0, size())
        if (_Mysize <= _Off) {
            _Xran();
        }
    }

    constexpr size_type _Clamp_suffix_size(const size_type _Off, const size_type _Size) const
        noexcept { // trims _Size to the longest it can be assuming a string at/after _Off
        return _Min_value(_Size, _Mysize - _Off);
    }

    [[noreturn]] static void _Xran() { // report an out_of_range error
        _Xout_of_range("invalid string_view position");
    }

    const_pointer _Mydata;
    size_type _Mysize;
};


// FUNCTION TEMPLATES operator== FOR basic_string_view
template <class _Elem, class _Traits>
_NODISCARD constexpr bool operator==(const basic_string_view<_Elem, _Traits> _Lhs,
    const basic_string_view<_Elem, _Traits> _Rhs) noexcept { // compare basic_string_view instances for equality
    return _Lhs._Equal(_Rhs);
}

template <class _Elem, class _Traits, int = 1> // TRANSITION, VSO#409326
_NODISCARD constexpr bool operator==(const _Identity_t<basic_string_view<_Elem, _Traits>> _Lhs,
    const basic_string_view<_Elem, _Traits>
        _Rhs) noexcept { // compare objects convertible to basic_string_view instances for equality
    return _Lhs._Equal(_Rhs);
}

template <class _Elem, class _Traits, int = 2> // TRANSITION, VSO#409326
_NODISCARD constexpr bool operator==(const basic_string_view<_Elem, _Traits> _Lhs,
    const _Identity_t<basic_string_view<_Elem, _Traits>>
        _Rhs) noexcept { // compare objects convertible to basic_string_view instances for equality
    return _Lhs._Equal(_Rhs);
}


// FUNCTION TEMPLATES operator!= FOR basic_string_view
template <class _Elem, class _Traits>
_NODISCARD constexpr bool operator!=(const basic_string_view<_Elem, _Traits> _Lhs,
    const basic_string_view<_Elem, _Traits> _Rhs) noexcept { // compare basic_string_view instances for inequality
    return !_Lhs._Equal(_Rhs);
}

template <class _Elem, class _Traits, int = 1> // TRANSITION, VSO#409326
_NODISCARD constexpr bool operator!=(const _Identity_t<basic_string_view<_Elem, _Traits>> _Lhs,
    const basic_string_view<_Elem, _Traits>
        _Rhs) noexcept { // compare objects convertible to basic_string_view instances for inequality
    return !_Lhs._Equal(_Rhs);
}

template <class _Elem, class _Traits, int = 2> // TRANSITION, VSO#409326
_NODISCARD constexpr bool operator!=(const basic_string_view<_Elem, _Traits> _Lhs,
    const _Identity_t<basic_string_view<_Elem, _Traits>>
        _Rhs) noexcept { // compare objects convertible to basic_string_view instances for inequality
    return !_Lhs._Equal(_Rhs);
}


// FUNCTION TEMPLATES operator< FOR basic_string_view
template <class _Elem, class _Traits>
_NODISCARD constexpr bool operator<(const basic_string_view<_Elem, _Traits> _Lhs,
    const basic_string_view<_Elem, _Traits> _Rhs) noexcept { // less-than compare basic_string_view instances
    return _Lhs.compare(_Rhs) < 0;
}

template <class _Elem, class _Traits, int = 1> // TRANSITION, VSO#409326
_NODISCARD constexpr bool operator<(const _Identity_t<basic_string_view<_Elem, _Traits>> _Lhs,
    const basic_string_view<_Elem, _Traits>
        _Rhs) noexcept { // less-than compare objects convertible to basic_string_view instances
    return _Lhs.compare(_Rhs) < 0;
}

template <class _Elem, class _Traits, int = 2> // TRANSITION, VSO#409326
_NODISCARD constexpr bool operator<(const basic_string_view<_Elem, _Traits> _Lhs,
    const _Identity_t<basic_string_view<_Elem, _Traits>>
        _Rhs) noexcept { // less-than compare objects convertible to basic_string_view instances
    return _Lhs.compare(_Rhs) < 0;
}


// FUNCTION TEMPLATES operator> FOR basic_string_view
template <class _Elem, class _Traits>
_NODISCARD constexpr bool operator>(const basic_string_view<_Elem, _Traits> _Lhs,
    const basic_string_view<_Elem, _Traits> _Rhs) noexcept { // greater-than compare basic_string_view instances
    return _Lhs.compare(_Rhs) > 0;
}

template <class _Elem, class _Traits, int = 1> // TRANSITION, VSO#409326
_NODISCARD constexpr bool operator>(const _Identity_t<basic_string_view<_Elem, _Traits>> _Lhs,
    const basic_string_view<_Elem, _Traits>
        _Rhs) noexcept { // greater-than compare objects convertible to basic_string_view instances
    return _Lhs.compare(_Rhs) > 0;
}

template <class _Elem, class _Traits, int = 2> // TRANSITION, VSO#409326
_NODISCARD constexpr bool operator>(const basic_string_view<_Elem, _Traits> _Lhs,
    const _Identity_t<basic_string_view<_Elem, _Traits>>
        _Rhs) noexcept { // greater-than compare objects convertible to basic_string_view instances
    return _Lhs.compare(_Rhs) > 0;
}


// FUNCTION TEMPLATES operator<= FOR basic_string_view
template <class _Elem, class _Traits>
_NODISCARD constexpr bool operator<=(const basic_string_view<_Elem, _Traits> _Lhs,
    const basic_string_view<_Elem, _Traits> _Rhs) noexcept { // less-than-or-equal compare basic_string_view instances
    return _Lhs.compare(_Rhs) <= 0;
}

template <class _Elem, class _Traits, int = 1> // TRANSITION, VSO#409326
_NODISCARD constexpr bool operator<=(const _Identity_t<basic_string_view<_Elem, _Traits>> _Lhs,
    const basic_string_view<_Elem, _Traits>
        _Rhs) noexcept { // less-than-or-equal compare objects convertible to basic_string_view instances
    return _Lhs.compare(_Rhs) <= 0;
}

template <class _Elem, class _Traits, int = 2> // TRANSITION, VSO#409326
_NODISCARD constexpr bool operator<=(const basic_string_view<_Elem, _Traits> _Lhs,
    const _Identity_t<basic_string_view<_Elem, _Traits>>
        _Rhs) noexcept { // less-than-or-equal compare objects convertible to basic_string_view instances
    return _Lhs.compare(_Rhs) <= 0;
}


// FUNCTION TEMPLATES operator>= FOR basic_string_view
template <class _Elem, class _Traits>
_NODISCARD constexpr bool operator>=(const basic_string_view<_Elem, _Traits> _Lhs,
    const basic_string_view<_Elem, _Traits>
        _Rhs) noexcept { // greater-than-or-equal compare basic_string_view instances
    return _Lhs.compare(_Rhs) >= 0;
}

template <class _Elem, class _Traits, int = 1> // TRANSITION, VSO#409326
_NODISCARD constexpr bool operator>=(const _Identity_t<basic_string_view<_Elem, _Traits>> _Lhs,
    const basic_string_view<_Elem, _Traits>
        _Rhs) noexcept { // greater-than-or-equal compare objects convertible to basic_string_view instances
    return _Lhs.compare(_Rhs) >= 0;
}

template <class _Elem, class _Traits, int = 2> // TRANSITION, VSO#409326
_NODISCARD constexpr bool operator>=(const basic_string_view<_Elem, _Traits> _Lhs,
    const _Identity_t<basic_string_view<_Elem, _Traits>>
        _Rhs) noexcept { // greater-than-or-equal compare objects convertible to basic_string_view instances
    return _Lhs.compare(_Rhs) >= 0;
}


// TYPEDEFS FOR basic_string_view
using string_view    = basic_string_view<char>;
using u16string_view = basic_string_view<char16_t>;
using u32string_view = basic_string_view<char32_t>;
using wstring_view   = basic_string_view<wchar_t>;


// STRUCT TEMPLATE SPECIALIZATION hash FOR basic_string_view
template <class _Elem, class _Traits>
struct hash<basic_string_view<_Elem, _Traits>> { // hash functor for basic_string_view
    _CXX17_DEPRECATE_ADAPTOR_TYPEDEFS typedef basic_string_view<_Elem, _Traits> argument_type;
    _CXX17_DEPRECATE_ADAPTOR_TYPEDEFS typedef size_t result_type;

    _NODISCARD size_t operator()(const basic_string_view<_Elem, _Traits> _Keyval) const
        noexcept { // hash _Keyval to size_t value by pseudorandomizing transform
        return _Hash_array_representation(_Keyval.data(), _Keyval.size());
    }
};

template <class _Elem, class _Traits>
inline basic_ostream<_Elem, _Traits>& operator<<(
    basic_ostream<_Elem, _Traits>& _Ostr, const basic_string_view<_Elem, _Traits> _Str) { // insert _Str into _Ostr
    return _Insert_string(_Ostr, _Str.data(), _Str.size());
}


// basic_string_view LITERALS
inline namespace literals {
    inline namespace string_view_literals {
        _NODISCARD constexpr string_view operator"" sv(
            const char* _Str, size_t _Len) noexcept { // construct string_view from [_Str, _Str + _Len)
            return string_view(_Str, _Len);
        }

        _NODISCARD constexpr wstring_view operator"" sv(
            const wchar_t* _Str, size_t _Len) noexcept { // construct wstring_view from [_Str, _Str + _Len)
            return wstring_view(_Str, _Len);
        }

        _NODISCARD constexpr u16string_view operator"" sv(
            const char16_t* _Str, size_t _Len) noexcept { // construct u16string_view from [_Str, _Str + _Len)
            return u16string_view(_Str, _Len);
        }

        _NODISCARD constexpr u32string_view operator"" sv(
            const char32_t* _Str, size_t _Len) noexcept { // construct u32string_view from [_Str, _Str + _Len)
            return u32string_view(_Str, _Len);
        }
    } // namespace string_view_literals
} // namespace literals
#endif // _HAS_CXX17

// CLASS TEMPLATE _String_const_iterator
template <class _Mystr>
class _String_const_iterator : public _Iterator_base { // iterator for immutable string
public:
    using iterator_category = random_access_iterator_tag;

    using value_type      = typename _Mystr::value_type;
    using difference_type = typename _Mystr::difference_type;
    using pointer         = typename _Mystr::const_pointer;
    using reference       = const value_type&;

    _String_const_iterator() : _Ptr() { // construct with null pointer
    }

    _String_const_iterator(pointer _Parg, const _Container_base* _Pstring)
        : _Ptr(_Parg) { // construct with pointer _Parg
        this->_Adopt(_Pstring);
    }

    _NODISCARD reference operator*() const { // return designated object
#if _ITERATOR_DEBUG_LEVEL >= 1
        _STL_VERIFY(_Ptr, "cannot dereference value-initialized string iterator");
        const auto _Mycont = static_cast<const _Mystr*>(this->_Getcont());
        _STL_VERIFY(_Mycont, "cannot dereference string iterator because the iterator was"
                             " invalidated (e.g. reallocation occurred, or the string was destroyed)");
        const auto _Contptr = _Mycont->_Myptr();
        const auto _Rawptr  = _Unfancy(_Ptr);
        _STL_VERIFY(_Contptr <= _Rawptr && _Rawptr < _Contptr + _Mycont->_Mysize,
            "cannot dereference string iterator because it is out of range (e.g. an end iterator)");
#endif // _ITERATOR_DEBUG_LEVEL >= 1

        _Analysis_assume_(_Ptr);
        return *_Ptr;
    }

    _NODISCARD pointer operator->() const { // return pointer to class object
        return pointer_traits<pointer>::pointer_to(**this);
    }

    _String_const_iterator& operator++() { // preincrement
#if _ITERATOR_DEBUG_LEVEL >= 1
        _STL_VERIFY(_Ptr, "cannot increment value-initialized string iterator");
        const auto _Mycont = static_cast<const _Mystr*>(this->_Getcont());
        _STL_VERIFY(_Mycont, "cannot increment string iterator because the iterator was"
                             " invalidated (e.g. reallocation occurred, or the string was destroyed)");
        _STL_VERIFY(_Unfancy(_Ptr) < _Mycont->_Myptr() + _Mycont->_Mysize, "cannot increment string iterator past end");
#endif // _ITERATOR_DEBUG_LEVEL >= 1

        ++_Ptr;
        return *this;
    }

    _String_const_iterator operator++(int) { // postincrement
        _String_const_iterator _Tmp = *this;
        ++*this;
        return _Tmp;
    }

    _String_const_iterator& operator--() { // predecrement
#if _ITERATOR_DEBUG_LEVEL >= 1
        _STL_VERIFY(_Ptr, "cannot decrement value-initialized string iterator");
        const auto _Mycont = static_cast<const _Mystr*>(this->_Getcont());
        _STL_VERIFY(_Mycont, "cannot decrement string iterator because the iterator was"
                             " invalidated (e.g. reallocation occurred, or the string was destroyed)");
        _STL_VERIFY(_Mycont->_Myptr() < _Unfancy(_Ptr), "cannot decrement string iterator before begin");
#endif // _ITERATOR_DEBUG_LEVEL >= 1

        --_Ptr;
        return *this;
    }

    _String_const_iterator operator--(int) { // postdecrement
        _String_const_iterator _Tmp = *this;
        --*this;
        return _Tmp;
    }

    void _Verify_offset(const difference_type _Off) const noexcept {
#if _ITERATOR_DEBUG_LEVEL >= 1
        if (_Off == 0) {
            return;
        }

        _STL_ASSERT(_Ptr, "cannot seek value-initialized string iterator");
        const auto _Mycont = static_cast<const _Mystr*>(this->_Getcont());
        _STL_ASSERT(_Mycont, "cannot seek string iterator because the iterator was"
                             " invalidated (e.g. reallocation occurred, or the string was destroyed)");
        const auto _Contptr = _Mycont->_Myptr();
        const auto _Rawptr  = _Unfancy(_Ptr);

        if (_Off < 0) {
#pragma warning(suppress : 4146) // unary minus operator applied to unsigned type, result still unsigned
            _STL_VERIFY(_Contptr - _Rawptr <= _Off, "cannot seek string iterator before begin");
        }

        if (_Off > 0) {
            using _Size_type = typename _Mystr::size_type;
            const auto _Left = _Mycont->_Mysize - static_cast<_Size_type>(_Rawptr - _Contptr);
            _STL_VERIFY(static_cast<_Size_type>(_Off) <= _Left, "cannot seek string iterator after end");
        }
#else // ^^^ _ITERATOR_DEBUG_LEVEL >= 1 ^^^ // vvv _ITERATOR_DEBUG_LEVEL == 0 vvv
        (void) _Off;
#endif // _ITERATOR_DEBUG_LEVEL >= 1
    }

    _String_const_iterator& operator+=(const difference_type _Off) { // increment by integer
#if _ITERATOR_DEBUG_LEVEL >= 1
        _Verify_offset(_Off);
#endif // _ITERATOR_DEBUG_LEVEL >= 1
        _Ptr += _Off;
        return *this;
    }

    _NODISCARD _String_const_iterator operator+(const difference_type _Off) const { // return this + integer
        _String_const_iterator _Tmp = *this;
        return _Tmp += _Off;
    }

    _String_const_iterator& operator-=(const difference_type _Off) { // decrement by integer
        return *this += -_Off;
    }

    _NODISCARD _String_const_iterator operator-(const difference_type _Off) const { // return this - integer
        _String_const_iterator _Tmp = *this;
        return _Tmp -= _Off;
    }

    _NODISCARD difference_type operator-(const _String_const_iterator& _Right) const { // return difference of iterators
        _Compat(_Right);
        return _Ptr - _Right._Ptr;
    }

    _NODISCARD reference operator[](const difference_type _Off) const { // subscript
        return *(*this + _Off);
    }

    _NODISCARD bool operator==(const _String_const_iterator& _Right) const { // test for iterator equality
        _Compat(_Right);
        return _Ptr == _Right._Ptr;
    }

    _NODISCARD bool operator!=(const _String_const_iterator& _Right) const { // test for iterator inequality
        return !(*this == _Right);
    }

    _NODISCARD bool operator<(const _String_const_iterator& _Right) const { // test if this < _Right
        _Compat(_Right);
        return _Ptr < _Right._Ptr;
    }

    _NODISCARD bool operator>(const _String_const_iterator& _Right) const { // test if this > _Right
        return _Right < *this;
    }

    _NODISCARD bool operator<=(const _String_const_iterator& _Right) const { // test if this <= _Right
        return !(_Right < *this);
    }

    _NODISCARD bool operator>=(const _String_const_iterator& _Right) const { // test if this >= _Right
        return !(*this < _Right);
    }

    void _Compat(const _String_const_iterator& _Right) const { // test for compatible iterator pair
#if _ITERATOR_DEBUG_LEVEL >= 1
        _STL_VERIFY(this->_Getcont() == _Right._Getcont(), "string iterators incompatible (e.g."
                                                           " point to different string instances)");
#else // ^^^ _ITERATOR_DEBUG_LEVEL >= 1 ^^^ // vvv _ITERATOR_DEBUG_LEVEL == 0 vvv
        (void) _Right;
#endif // _ITERATOR_DEBUG_LEVEL
    }

#if _ITERATOR_DEBUG_LEVEL >= 1
    friend void _Verify_range(const _String_const_iterator& _First, const _String_const_iterator& _Last) {
        _STL_VERIFY(_First._Getcont() == _Last._Getcont(), "string iterators in range are from different containers");
        _STL_VERIFY(_First._Ptr <= _Last._Ptr, "string iterator range transposed");
    }
#endif // _ITERATOR_DEBUG_LEVEL >= 1

    using _Prevent_inheriting_unwrap = _String_const_iterator;

    _NODISCARD pointer _Unwrapped() const {
        return _Ptr;
    }

    void _Seek_to(pointer _It) {
        _Ptr = _It;
    }

    pointer _Ptr; // pointer to element in string
};

template <class _Mystr>
_NODISCARD inline _String_const_iterator<_Mystr> operator+(
    typename _String_const_iterator<_Mystr>::difference_type _Off,
    _String_const_iterator<_Mystr> _Next) { // add offset to iterator
    return _Next += _Off;
}

// CLASS TEMPLATE _String_iterator
template <class _Mystr>
class _String_iterator : public _String_const_iterator<_Mystr> { // iterator for mutable string
public:
    using _Mybase           = _String_const_iterator<_Mystr>;
    using iterator_category = random_access_iterator_tag;

    using value_type      = typename _Mystr::value_type;
    using difference_type = typename _Mystr::difference_type;
    using pointer         = typename _Mystr::pointer;
    using reference       = value_type&;

    _String_iterator() { // construct with null string pointer
    }

    _String_iterator(pointer _Parg, const _Container_base* _Pstring)
        : _Mybase(_Parg, _Pstring) { // construct with pointer _Parg
    }

    _NODISCARD reference operator*() const { // return designated object
        return const_cast<reference>(_Mybase::operator*());
    }

    _NODISCARD pointer operator->() const { // return pointer to class object
        return pointer_traits<pointer>::pointer_to(**this);
    }

    _String_iterator& operator++() { // preincrement
        ++*(_Mybase*) this;
        return *this;
    }

    _String_iterator operator++(int) { // postincrement
        _String_iterator _Tmp = *this;
        ++*this;
        return _Tmp;
    }

    _String_iterator& operator--() { // predecrement
        --*(_Mybase*) this;
        return *this;
    }

    _String_iterator operator--(int) { // postdecrement
        _String_iterator _Tmp = *this;
        --*this;
        return _Tmp;
    }

    _String_iterator& operator+=(const difference_type _Off) { // increment by integer
        *(_Mybase*) this += _Off;
        return *this;
    }

    _NODISCARD _String_iterator operator+(const difference_type _Off) const { // return this + integer
        _String_iterator _Tmp = *this;
        return _Tmp += _Off;
    }

    _String_iterator& operator-=(const difference_type _Off) { // decrement by integer
        return *this += -_Off;
    }

    _NODISCARD _String_iterator operator-(const difference_type _Off) const { // return this - integer
        _String_iterator _Tmp = *this;
        return _Tmp -= _Off;
    }

    _NODISCARD difference_type operator-(const _Mybase& _Right) const { // return difference of iterators
        return *(_Mybase*) this - _Right;
    }

    _NODISCARD reference operator[](const difference_type _Off) const { // subscript
        return *(*this + _Off);
    }

    using _Prevent_inheriting_unwrap = _String_iterator;

    _NODISCARD pointer _Unwrapped() const {
        return _Const_cast(this->_Ptr);
    }
};

template <class _Mystr>
_NODISCARD inline _String_iterator<_Mystr> operator+(typename _String_iterator<_Mystr>::difference_type _Off,
    _String_iterator<_Mystr> _Next) { // add offset to iterator
    return _Next += _Off;
}

// basic_string TYPE WRAPPERS
template <class _Value_type, class _Size_type, class _Difference_type, class _Pointer, class _Const_pointer,
    class _Reference, class _Const_reference>
struct _String_iter_types { // wraps types needed by iterators
    using value_type      = _Value_type;
    using size_type       = _Size_type;
    using difference_type = _Difference_type;
    using pointer         = _Pointer;
    using const_pointer   = _Const_pointer;
};

// CLASS TEMPLATE _String_val
template <class _Val_types>
class _String_val : public _Container_base { // base class for basic_string to hold data
public:
    using value_type      = typename _Val_types::value_type;
    using size_type       = typename _Val_types::size_type;
    using difference_type = typename _Val_types::difference_type;
    using pointer         = typename _Val_types::pointer;
    using const_pointer   = typename _Val_types::const_pointer;
    using reference       = value_type&;
    using const_reference = const value_type&;

    _String_val() : _Bx(), _Mysize(0), _Myres(0) { // initialize values
    }

    // length of internal buffer, [1, 16]:
    static constexpr size_type _BUF_SIZE = 16 / sizeof(value_type) < 1 ? 1 : 16 / sizeof(value_type);
    // roundup mask for allocated buffers, [0, 15]:
    static constexpr size_type _ALLOC_MASK =
        sizeof(value_type) <= 1
            ? 15
            : sizeof(value_type) <= 2 ? 7 : sizeof(value_type) <= 4 ? 3 : sizeof(value_type) <= 8 ? 1 : 0;

    value_type* _Myptr() { // determine current pointer to buffer for mutable string
        value_type* _Result = _Bx._Buf;
        if (_Large_string_engaged()) {
            _Result = _Unfancy(_Bx._Ptr);
        }

        return _Result;
    }

    const value_type* _Myptr() const { // determine current pointer to buffer for immutable string
        const value_type* _Result = _Bx._Buf;
        if (_Large_string_engaged()) {
            _Result = _Unfancy(_Bx._Ptr);
        }

        return _Result;
    }

    bool _Large_string_engaged() const { // returns whether the large string mode (allocated memory) is engaged
        return _BUF_SIZE <= _Myres;
    }

    void _Check_offset(const size_type _Off) const { // checks whether _Off is in the bounds of [0, size()]
        if (_Mysize < _Off) {
            _Xran();
        }
    }

    void _Check_offset_exclusive(const size_type _Off) const { // checks whether _Off is in the bounds of [0, size())
        if (_Mysize <= _Off) {
            _Xran();
        }
    }

    [[noreturn]] static void _Xran() { // report an out_of_range error
        _Xout_of_range("invalid string position");
    }

    size_type _Clamp_suffix_size(const size_type _Off, const size_type _Size) const
        noexcept { // trims _Size to the longest it can be assuming a string at/after _Off
        return _Min_value(_Size, _Mysize - _Off);
    }

    union _Bxty { // storage for small buffer or pointer to larger one
        _Bxty() { // user-provided, for fancy pointers
        }

        ~_Bxty() noexcept { // user-provided, for fancy pointers
        }

        value_type _Buf[_BUF_SIZE];
        pointer _Ptr;
        char _Alias[_BUF_SIZE]; // retained for /clr bincompat; unused
    } _Bx;

    size_type _Mysize; // current length of string
    size_type _Myres; // current storage reserved for string
};

// CLASS TEMPLATE basic_string
template <class _Ty>
constexpr size_t _Size_after_ebco_v = is_empty_v<_Ty> ? 0 : sizeof(_Ty); // get _Ty's size after being EBCO'd

template <class _Elem, class _Traits = char_traits<_Elem>, class _Alloc = allocator<_Elem>>
class basic_string { // null-terminated transparent array of elements
private:
    friend _Tidy_deallocate_guard<basic_string>;

    using _Alty        = _Rebind_alloc_t<_Alloc, _Elem>;
    using _Alty_traits = allocator_traits<_Alty>;

    using _Scary_val = _String_val<conditional_t<_Is_simple_alloc_v<_Alty>, _Simple_types<_Elem>,
        _String_iter_types<_Elem, typename _Alty_traits::size_type, typename _Alty_traits::difference_type,
            typename _Alty_traits::pointer, typename _Alty_traits::const_pointer, _Elem&, const _Elem&>>>;

    static_assert(!_ENFORCE_MATCHING_ALLOCATORS || is_same_v<_Elem, typename _Alloc::value_type>,
        _MISMATCHED_ALLOCATOR_MESSAGE("basic_string<T, Traits, Allocator>", "T"));

    static_assert(is_same_v<_Elem, typename _Traits::char_type>,
        "N4659 24.3.2.1 [string.require]/3 requires that the supplied "
        "char_traits character type match the string's character type.");

public:
    using traits_type    = _Traits;
    using allocator_type = _Alloc;

    using value_type      = _Elem;
    using size_type       = typename _Alty_traits::size_type;
    using difference_type = typename _Alty_traits::difference_type;
    using pointer         = typename _Alty_traits::pointer;
    using const_pointer   = typename _Alty_traits::const_pointer;
    using reference       = value_type&;
    using const_reference = const value_type&;

    using iterator       = _String_iterator<_Scary_val>;
    using const_iterator = _String_const_iterator<_Scary_val>;

    using reverse_iterator       = _STD reverse_iterator<iterator>;
    using const_reverse_iterator = _STD reverse_iterator<const_iterator>;

private:
    static constexpr auto _BUF_SIZE   = _Scary_val::_BUF_SIZE;
    static constexpr auto _ALLOC_MASK = _Scary_val::_ALLOC_MASK;

    // When doing swap / move by memcpy, we are touching:
    //   _String_val::_Bx::_Buf (type is array of _Elem)
    //   _String_val::_Bx::_Ptr (type is pointer)
    //   _String_val::_Mysize   (type is size_type)
    //   _String_val::_Myres    (type is size_type)
    // N4659 24.1 [strings.general]/1 says _Elem must be a non-array POD, so memcpy is safe.
    // We need to ask if pointer is safe to memcpy.
    // size_type must be an unsigned integral type so memcpy is safe.
    // We also need to disable memcpy if the user has supplied _Traits, since
    //   they can observe traits::assign and similar.
    using _Use_memcpy_move = bool_constant<_Is_specialization_v<_Traits, char_traits> && is_trivial_v<pointer>>;
    // This offset skips over the _Container_base members, if any
    static constexpr size_t _Memcpy_move_offset = _Size_after_ebco_v<_Container_base>;
    static constexpr size_t _Memcpy_move_size   = sizeof(_Scary_val) - _Memcpy_move_offset;

    template <class _Iter>
    using _Is_elem_cptr = bool_constant<_Is_any_of_v<_Iter, const _Elem* const, _Elem* const, const _Elem*, _Elem*>>;

#if _HAS_CXX17
    template <class _StringViewIsh>
    using _Is_string_view_ish =
        enable_if_t<conjunction_v<is_convertible<const _StringViewIsh&, basic_string_view<_Elem, _Traits>>,
            negation<is_convertible<const _StringViewIsh&, const _Elem*>>>>;
#endif // _HAS_CXX17

public:
    basic_string(const basic_string& _Right)
        : _Mypair(_One_then_variadic_args_t(),
              _Alty_traits::select_on_container_copy_construction(_Right._Getal())) { // construct by copying _Right
        auto&& _Alproxy = _GET_PROXY_ALLOCATOR(_Alty, _Getal());
        _Container_proxy_ptr<_Alty> _Proxy(_Alproxy, _Get_data());
        _Construct_lv_contents(_Right);
        _Proxy._Release();
    }

    basic_string(const basic_string& _Right, const _Alloc& _Al)
        : _Mypair(_One_then_variadic_args_t(), _Al) { // construct by copying with allocator
        auto&& _Alproxy = _GET_PROXY_ALLOCATOR(_Alty, _Getal());
        _Container_proxy_ptr<_Alty> _Proxy(_Alproxy, _Get_data());
        _Construct_lv_contents(_Right);
        _Proxy._Release();
    }

    basic_string() _NOEXCEPT_COND(is_nothrow_default_constructible_v<_Alty>)
        : _Mypair(_Zero_then_variadic_args_t()) { // construct empty string
        _Get_data()._Alloc_proxy(_GET_PROXY_ALLOCATOR(_Alty, _Getal()));
        _Tidy_init();
    }

    explicit basic_string(const _Alloc& _Al) noexcept
        : _Mypair(_One_then_variadic_args_t(), _Al) { // construct empty string with allocator
        _Get_data()._Alloc_proxy(_GET_PROXY_ALLOCATOR(_Alty, _Getal()));
        _Tidy_init();
    }

    basic_string(const basic_string& _Right, const size_type _Roff, const _Alloc& _Al = _Alloc())
        : _Mypair(_One_then_variadic_args_t(), _Al) { // construct from _Right [_Roff, <end>)
        auto&& _Alproxy = _GET_PROXY_ALLOCATOR(_Alty, _Getal());
        _Container_proxy_ptr<_Alty> _Proxy(_Alproxy, _Get_data());
        _Tidy_init();
        assign(_Right, _Roff, npos);
        _Proxy._Release();
    }

    basic_string(
        const basic_string& _Right, const size_type _Roff, const size_type _Count, const _Alloc& _Al = _Alloc())
        : _Mypair(_One_then_variadic_args_t(), _Al) { // construct from _Right [_Roff, _Roff + _Count)
        auto&& _Alproxy = _GET_PROXY_ALLOCATOR(_Alty, _Getal());
        _Container_proxy_ptr<_Alty> _Proxy(_Alproxy, _Get_data());
        _Tidy_init();
        assign(_Right, _Roff, _Count);
        _Proxy._Release();
    }

    basic_string(_In_reads_(_Count) const _Elem* const _Ptr, _CRT_GUARDOVERFLOW const size_type _Count)
        : _Mypair(_Zero_then_variadic_args_t()) { // construct from [_Ptr, _Ptr + _Count)
        auto&& _Alproxy = _GET_PROXY_ALLOCATOR(_Alty, _Getal());
        _Container_proxy_ptr<_Alty> _Proxy(_Alproxy, _Get_data());
        _Tidy_init();
        assign(_Ptr, _Count);
        _Proxy._Release();
    }

    basic_string(
        _In_reads_(_Count) const _Elem* const _Ptr, _CRT_GUARDOVERFLOW const size_type _Count, const _Alloc& _Al)
        : _Mypair(_One_then_variadic_args_t(), _Al) { // construct from [_Ptr, _Ptr + _Count) with allocator
        auto&& _Alproxy = _GET_PROXY_ALLOCATOR(_Alty, _Getal());
        _Container_proxy_ptr<_Alty> _Proxy(_Alproxy, _Get_data());
        _Tidy_init();
        assign(_Ptr, _Count);
        _Proxy._Release();
    }

    basic_string(_In_z_ const _Elem* const _Ptr)
        : _Mypair(_Zero_then_variadic_args_t()) { // construct from [_Ptr, <null>)
        auto&& _Alproxy = _GET_PROXY_ALLOCATOR(_Alty, _Getal());
        _Container_proxy_ptr<_Alty> _Proxy(_Alproxy, _Get_data());
        _Tidy_init();
        assign(_Ptr);
        _Proxy._Release();
    }

#if _HAS_CXX17
    template <class _Alloc2 = _Alloc, enable_if_t<_Is_allocator<_Alloc2>::value, int> = 0>
#endif // _HAS_CXX17
    basic_string(_In_z_ const _Elem* const _Ptr, const _Alloc& _Al)
        : _Mypair(_One_then_variadic_args_t(), _Al) { // construct from [_Ptr, <null>) with allocator
        auto&& _Alproxy = _GET_PROXY_ALLOCATOR(_Alty, _Getal());
        _Container_proxy_ptr<_Alty> _Proxy(_Alproxy, _Get_data());
        _Tidy_init();
        assign(_Ptr);
        _Proxy._Release();
    }

    basic_string(_CRT_GUARDOVERFLOW const size_type _Count, const _Elem _Ch)
        : _Mypair(_Zero_then_variadic_args_t()) { // construct from _Count * _Ch
        auto&& _Alproxy = _GET_PROXY_ALLOCATOR(_Alty, _Getal());
        _Container_proxy_ptr<_Alty> _Proxy(_Alproxy, _Get_data());
        _Tidy_init();
        assign(_Count, _Ch);
        _Proxy._Release();
    }

#if _HAS_CXX17
    template <class _Alloc2 = _Alloc, enable_if_t<_Is_allocator<_Alloc2>::value, int> = 0>
#endif // _HAS_CXX17
    basic_string(_CRT_GUARDOVERFLOW const size_type _Count, const _Elem _Ch, const _Alloc& _Al)
        : _Mypair(_One_then_variadic_args_t(), _Al) { // construct from _Count * _Ch with allocator
        auto&& _Alproxy = _GET_PROXY_ALLOCATOR(_Alty, _Getal());
        _Container_proxy_ptr<_Alty> _Proxy(_Alproxy, _Get_data());
        _Tidy_init();
        assign(_Count, _Ch);
        _Proxy._Release();
    }

    template <class _Iter, class = enable_if_t<_Is_iterator_v<_Iter>>>
    basic_string(_Iter _First, _Iter _Last, const _Alloc& _Al = _Alloc())
        : _Mypair(_One_then_variadic_args_t(), _Al) { // construct from [_First, _Last) with optional allocator
        auto&& _Alproxy = _GET_PROXY_ALLOCATOR(_Alty, _Getal());
        _Container_proxy_ptr<_Alty> _Proxy(_Alproxy, _Get_data());
        _Tidy_init();
        _Adl_verify_range(_First, _Last);
        _Construct(_Get_unwrapped(_First), _Get_unwrapped(_Last), _Iter_cat_t<_Iter>());
        _Proxy._Release();
    }

    template <class _Iter>
    void _Construct(
        _Iter _First, const _Iter _Last, input_iterator_tag) { // initialize from [_First, _Last), input iterators
        _Tidy_deallocate_guard<basic_string> _Guard{this};
        for (; _First != _Last; ++_First) {
            push_back(*_First);
        }

        _Guard._Target = nullptr;
    }

    template <class _Iter>
    void _Construct(const _Iter _First, const _Iter _Last,
        forward_iterator_tag) { // initialize from [_First, _Last), forward iterators
        const size_type _Count = _Convert_size<size_type>(static_cast<size_t>(_STD distance(_First, _Last)));
        reserve(_Count);
        _Construct(_First, _Last, input_iterator_tag());
    }

    void _Construct(_Elem* const _First, _Elem* const _Last,
        random_access_iterator_tag) { // initialize from [_First, _Last), pointers
        if (_First != _Last) {
            assign(_First, _Convert_size<size_type>(static_cast<size_t>(_Last - _First)));
        }
    }

    void _Construct(const _Elem* const _First, const _Elem* const _Last,
        random_access_iterator_tag) { // initialize from [_First, _Last), const pointers
        if (_First != _Last) {
            assign(_First, _Convert_size<size_type>(static_cast<size_t>(_Last - _First)));
        }
    }

    basic_string(basic_string&& _Right) noexcept
        : _Mypair(_One_then_variadic_args_t(), _STD move(_Right._Getal())) { // construct by moving _Right
        _Get_data()._Alloc_proxy(_GET_PROXY_ALLOCATOR(_Alty, _Getal()));
        _Take_contents(_Right, _Use_memcpy_move{});
    }

    basic_string(basic_string&& _Right, const _Alloc& _Al)
        _NOEXCEPT_COND(_Alty_traits::is_always_equal::value) // strengthened
        : _Mypair(_One_then_variadic_args_t(), _Al) { // construct by moving _Right, allocator
        auto&& _Alproxy = _GET_PROXY_ALLOCATOR(_Alty, _Getal());
        _Container_proxy_ptr<_Alty> _Proxy(_Alproxy, _Get_data());
        if
            _CONSTEXPR_IF(!_Alty_traits::is_always_equal::value) {
                if (_Getal() != _Right._Getal()) {
                    _Construct_lv_contents(_Right);
                    _Proxy._Release();
                    return;
                }
            }

        _Take_contents(_Right, _Use_memcpy_move{});
        _Proxy._Release();
    }

#if _HAS_CXX17
    template <class _StringViewIsh, class = _Is_string_view_ish<_StringViewIsh>>
    explicit basic_string(const _StringViewIsh& _Right, const _Alloc& _Al = _Alloc())
        : _Mypair(_One_then_variadic_args_t(), _Al) { // construct from _Right using _Al
        auto&& _Alproxy = _GET_PROXY_ALLOCATOR(_Alty, _Getal());
        _Container_proxy_ptr<_Alty> _Proxy(_Alproxy, _Get_data());
        _Tidy_init();
        assign(_Right);
        _Proxy._Release();
    }

    template <class _StringViewIsh, class = _Is_string_view_ish<_StringViewIsh>>
    basic_string(
        const _StringViewIsh& _Right, const size_type _Roff, const size_type _Count, const _Alloc& _Al = _Alloc())
        : _Mypair(_One_then_variadic_args_t(), _Al) {
        // construct from _Right [_Roff, _Roff + _Count) using _Al
        auto&& _Alproxy = _GET_PROXY_ALLOCATOR(_Alty, _Getal());
        _Container_proxy_ptr<_Alty> _Proxy(_Alproxy, _Get_data());
        _Tidy_init();
        assign(_Right, _Roff, _Count);
        _Proxy._Release();
    }
#endif // _HAS_CXX17

private:
    void _Move_assign(basic_string& _Right, _Equal_allocators) noexcept {
        _Tidy_deallocate();
        _Pocma(_Getal(), _Right._Getal());
        _Take_contents(_Right, _Use_memcpy_move{});
    }

    void _Move_assign(basic_string& _Right, _Propagate_allocators) noexcept {
        if (_Getal() == _Right._Getal()) {
            _Move_assign(_Right, _Equal_allocators{});
        } else {
            // intentionally slams into noexcept on OOM, TRANSITION, VSO#466800
            auto& _My_data = _Get_data();
            _My_data._Orphan_all();
            _My_data._Reload_proxy(_GET_PROXY_ALLOCATOR(_Alty, _Getal()), _GET_PROXY_ALLOCATOR(_Alty, _Right._Getal()));
            _Pocma(_Getal(), _Right._Getal());
            _Take_contents(_Right, _Use_memcpy_move{});
        }
    }

    void _Move_assign(basic_string& _Right, _No_propagate_allocators) {
        if (_Getal() == _Right._Getal()) {
            _Move_assign(_Right, _Equal_allocators{});
        } else {
            auto& _Right_data = _Right._Get_data();
            assign(_Right_data._Myptr(), _Right_data._Mysize);
        }
    }

public:
    basic_string& operator=(basic_string&& _Right)
        _NOEXCEPT_COND(noexcept(_Move_assign(_Right, _Choose_pocma<_Alty>{}))) {
        if (this != _STD addressof(_Right)) {
            _Move_assign(_Right, _Choose_pocma<_Alty>{});
        }

        return *this;
    }

    basic_string& assign(basic_string&& _Right)
        _NOEXCEPT_COND(noexcept(*this = _STD move(_Right))) { // assign by moving _Right
        *this = _STD move(_Right);
        return *this;
    }

    void _Take_contents(basic_string& _Right, true_type) noexcept {
        // assign by stealing _Right's buffer, memcpy optimization
        // pre: this != &_Right
        // pre: allocator propagation (POCMA) from _Right, if necessary, is
        // complete pre: *this owns no memory, iterators orphaned (note:
        // _Buf/_Ptr/_Mysize/_Myres may be garbage init)
        auto& _Right_data = _Right._Get_data();

#if _ITERATOR_DEBUG_LEVEL != 0
        if (_Right_data._Large_string_engaged()) { // take ownership of _Right's iterators along with its buffer
            _Swap_proxy_and_iterators(_Right);
        } else {
            _Right._Orphan_all();
        }
#endif // _ITERATOR_DEBUG_LEVEL != 0

        const auto _My_data_mem = reinterpret_cast<unsigned char*>(_STD addressof(_Get_data())) + _Memcpy_move_offset;
        const auto _Right_data_mem =
            reinterpret_cast<unsigned char*>(_STD addressof(_Right_data)) + _Memcpy_move_offset;
        _CSTD memcpy(_My_data_mem, _Right_data_mem, _Memcpy_move_size);
        _Right._Tidy_init();
    }

    void _Take_contents(basic_string& _Right, false_type) noexcept {
        // assign by stealing _Right's buffer, general case
        // pre: this != &_Right
        // pre: allocator propagation (POCMA) from _Right, if necessary,
        // is complete pre: *this owns no memory, iterators orphaned
        // (note: _Buf/_Ptr/_Mysize/_Myres may be garbage init)
        auto& _My_data    = _Get_data();
        auto& _Right_data = _Right._Get_data();
        if (_Right_data._Large_string_engaged()) { // steal buffer
            _Alty_traits::construct(_Getal(), _STD addressof(_My_data._Bx._Ptr), _Right_data._Bx._Ptr);
            _Right_data._Bx._Ptr = pointer();
            _Swap_proxy_and_iterators(_Right);
        } else { // copy small string buffer
            _Traits::copy(_My_data._Bx._Buf, _Right_data._Bx._Buf, _Right_data._Mysize + 1);
            _Right._Orphan_all();
        }

        _My_data._Mysize = _Right_data._Mysize;
        _My_data._Myres  = _Right_data._Myres;
        _Right._Tidy_init();
    }

    void _Construct_lv_contents(const basic_string& _Right) {
        // assign by copying data stored in _Right
        // pre: this != &_Right
        // pre: *this owns no memory, iterators orphaned (note:
        // _Buf/_Ptr/_Mysize/_Myres may be garbage init)
        auto& _My_data                = _Get_data();
        auto& _Right_data             = _Right._Get_data();
        const size_type _Right_size   = _Right_data._Mysize;
        const _Elem* const _Right_ptr = _Right_data._Myptr();
        if (_Right_size < _BUF_SIZE) { // stay small, don't allocate
            _Traits::copy(_My_data._Bx._Buf, _Right_ptr, _BUF_SIZE);
            _My_data._Mysize = _Right_size;
            _My_data._Myres  = _BUF_SIZE - 1;
            return;
        }

        auto& _Al                     = _Getal();
        const size_type _New_capacity = _Min_value(_Right_size | _ALLOC_MASK, max_size());
        const pointer _New_array      = _Al.allocate(_New_capacity + 1); // throws
        _Alty_traits::construct(_Al, _STD addressof(_My_data._Bx._Ptr), _New_array);
        _Traits::copy(_Unfancy(_New_array), _Right_ptr, _Right_size + 1);
        _My_data._Mysize = _Right_size;
        _My_data._Myres  = _New_capacity;
    }

    basic_string(initializer_list<_Elem> _Ilist, const _Alloc& _Al = allocator_type())
        : _Mypair(_One_then_variadic_args_t(), _Al) {
        // construct from initializer_list
        auto&& _Alproxy = _GET_PROXY_ALLOCATOR(_Alty, _Getal());
        _Container_proxy_ptr<_Alty> _Proxy(_Alproxy, _Get_data());
        _Tidy_init();
        assign(_Ilist.begin(), _Convert_size<size_type>(_Ilist.size()));
        _Proxy._Release();
    }

    basic_string& operator=(initializer_list<_Elem> _Ilist) { // assign initializer_list
        return assign(_Ilist.begin(), _Convert_size<size_type>(_Ilist.size()));
    }

    basic_string& operator+=(initializer_list<_Elem> _Ilist) { // append initializer_list
        return append(_Ilist.begin(), _Convert_size<size_type>(_Ilist.size()));
    }

    basic_string& assign(initializer_list<_Elem> _Ilist) { // assign initializer_list
        return assign(_Ilist.begin(), _Convert_size<size_type>(_Ilist.size()));
    }

    basic_string& append(initializer_list<_Elem> _Ilist) { // append initializer_list
        return append(_Ilist.begin(), _Convert_size<size_type>(_Ilist.size()));
    }

    iterator insert(const const_iterator _Where, const initializer_list<_Elem> _Ilist) { // insert initializer_list
        const difference_type _Off = _Where - begin();
        insert(static_cast<size_type>(_Off), _Ilist.begin(), _Convert_size<size_type>(_Ilist.size()));
        return begin() + _Off;
    }

    basic_string& replace(const const_iterator _First, const const_iterator _Last,
        const initializer_list<_Elem> _Ilist) { // replace with initializer_list
        return replace(static_cast<size_type>(_First - begin()), static_cast<size_type>(_Last - _First), _Ilist.begin(),
            _Convert_size<size_type>(_Ilist.size()));
    }

    ~basic_string() noexcept { // destroy the string
        _Tidy_deallocate();
#if _ITERATOR_DEBUG_LEVEL != 0
        auto&& _Alproxy = _GET_PROXY_ALLOCATOR(_Alty, _Getal());
        _Delete_plain(_Alproxy, _STD exchange(_Get_data()._Myproxy, nullptr));
#endif // _ITERATOR_DEBUG_LEVEL != 0
    }

    static constexpr auto npos{static_cast<size_type>(-1)};

private:
    void _Copy_assign(const basic_string& _Right, false_type) {
        _Pocca(_Getal(), _Right._Getal());
        auto& _Right_data = _Right._Get_data();
        assign(_Right_data._Myptr(), _Right_data._Mysize);
    }

    void _Copy_assign(const basic_string& _Right, true_type) {
        if (_Getal() == _Right._Getal()) {
            _Copy_assign(_Right, false_type{});
        } else {
            _Tidy_deallocate();
            _Get_data()._Reload_proxy(
                _GET_PROXY_ALLOCATOR(_Alty, _Getal()), _GET_PROXY_ALLOCATOR(_Alty, _Right._Getal()));
            _Pocca(_Getal(), _Right._Getal());
            auto& _Right_data = _Right._Get_data();
            assign(_Right_data._Myptr(), _Right_data._Mysize);
        }
    }

public:
    basic_string& operator=(const basic_string& _Right) { // assign _Right
        if (this != _STD addressof(_Right)) { // different, assign it
            _Copy_assign(_Right, _Choose_pocca<_Alty>{});
        }

        return *this;
    }

#if _HAS_CXX17
    template <class _StringViewIsh, class = _Is_string_view_ish<_StringViewIsh>>
    basic_string& operator=(const _StringViewIsh& _Right) { // assign _Right
        return assign(_Right);
    }
#endif // _HAS_CXX17

    basic_string& operator=(_In_z_ const _Elem* const _Ptr) { // assign [_Ptr, <null>)
        return assign(_Ptr);
    }

    basic_string& operator=(const _Elem _Ch) { // assign {_Ch, _Elem()}
        auto& _My_data    = _Get_data();
        _My_data._Mysize  = 1;
        _Elem* const _Ptr = _My_data._Myptr();
        _Traits::assign(_Ptr[0], _Ch);
        _Traits::assign(_Ptr[1], _Elem());
        return *this;
    }

    basic_string& operator+=(const basic_string& _Right) { // append _Right
        return append(_Right);
    }

#if _HAS_CXX17
    template <class _StringViewIsh, class = _Is_string_view_ish<_StringViewIsh>>
    basic_string& operator+=(const _StringViewIsh& _Right) { // append _Right
        return append(_Right);
    }
#endif // _HAS_CXX17

    basic_string& operator+=(_In_z_ const _Elem* const _Ptr) { // append [_Ptr, <null>)
        return append(_Ptr);
    }

    basic_string& operator+=(_Elem _Ch) { // append 1 * _Ch
        push_back(_Ch);
        return *this;
    }

    basic_string& append(const basic_string& _Right) { // append _Right
        auto& _Right_data = _Right._Get_data();
        return append(_Right_data._Myptr(), _Right_data._Mysize);
    }

    basic_string& append(const basic_string& _Right, const size_type _Roff,
        size_type _Count = npos) { // append _Right [_Roff, _Roff + _Count)
        auto& _Right_data = _Right._Get_data();
        _Right_data._Check_offset(_Roff);
        _Count = _Right_data._Clamp_suffix_size(_Roff, _Count);
        return append(_Right_data._Myptr() + _Roff, _Count);
    }

#if _HAS_CXX17
    template <class _StringViewIsh, class = _Is_string_view_ish<_StringViewIsh>>
    basic_string& append(const _StringViewIsh& _Right) { // append _Right
        const basic_string_view<_Elem, _Traits> _As_view = _Right;
        return append(_As_view.data(), _Convert_size<size_type>(_As_view.size()));
    }

    template <class _StringViewIsh, class = _Is_string_view_ish<_StringViewIsh>>
    basic_string& append(const _StringViewIsh& _Right, const size_type _Roff,
        const size_type _Count = npos) { // append _Right [_Roff, _Roff + _Count)
        basic_string_view<_Elem, _Traits> _As_view = _Right;
        return append(_As_view.substr(_Roff, _Count));
    }
#endif // _HAS_CXX17

    basic_string& append(_In_reads_(_Count) const _Elem* const _Ptr, _CRT_GUARDOVERFLOW const size_type _Count) {
        // append [_Ptr, _Ptr + _Count)
        auto& _My_data            = _Get_data();
        const size_type _Old_size = _My_data._Mysize;
        if (_Count <= _My_data._Myres - _Old_size) {
            _My_data._Mysize      = _Old_size + _Count;
            _Elem* const _Old_ptr = _My_data._Myptr();
            _Traits::move(_Old_ptr + _Old_size, _Ptr, _Count);
            _Traits::assign(_Old_ptr[_Old_size + _Count], _Elem());
            return *this;
        }

        return _Reallocate_grow_by(_Count,
            [](_Elem* const _New_ptr, const _Elem* const _Old_ptr, const size_type _Old_size, const _Elem* const _Ptr,
                const size_type _Count) {
                _Traits::copy(_New_ptr, _Old_ptr, _Old_size);
                _Traits::copy(_New_ptr + _Old_size, _Ptr, _Count);
                _Traits::assign(_New_ptr[_Old_size + _Count], _Elem());
            },
            _Ptr, _Count);
    }

    basic_string& append(_In_z_ const _Elem* const _Ptr) { // append [_Ptr, <null>)
        return append(_Ptr, _Convert_size<size_type>(_Traits::length(_Ptr)));
    }

    basic_string& append(_CRT_GUARDOVERFLOW const size_type _Count, const _Elem _Ch) { // append _Count * _Ch
        auto& _My_data            = _Get_data();
        const size_type _Old_size = _My_data._Mysize;
        if (_Count <= _My_data._Myres - _Old_size) {
            _My_data._Mysize      = _Old_size + _Count;
            _Elem* const _Old_ptr = _My_data._Myptr();
            _Traits::assign(_Old_ptr + _Old_size, _Count, _Ch);
            _Traits::assign(_Old_ptr[_Old_size + _Count], _Elem());
            return *this;
        }

        return _Reallocate_grow_by(_Count,
            [](_Elem* const _New_ptr, const _Elem* const _Old_ptr, const size_type _Old_size, const size_type _Count,
                const _Elem _Ch) {
                _Traits::copy(_New_ptr, _Old_ptr, _Old_size);
                _Traits::assign(_New_ptr + _Old_size, _Count, _Ch);
                _Traits::assign(_New_ptr[_Old_size + _Count], _Elem());
            },
            _Count, _Ch);
    }

    template <class _Iter, class = enable_if_t<_Is_iterator_v<_Iter>>>
    basic_string& append(const _Iter _First, const _Iter _Last) { // append [_First, _Last), input iterators
        return replace(end(), end(), _First, _Last);
    }

    basic_string& assign(const basic_string& _Right) { // assign _Right
        *this = _Right;
        return *this;
    }

    basic_string& assign(const basic_string& _Right, const size_type _Roff, size_type _Count = npos) {
        // assign _Right [_Roff, _Roff + _Count)
        auto& _Right_data = _Right._Get_data();
        _Right_data._Check_offset(_Roff);
        _Count = _Right_data._Clamp_suffix_size(_Roff, _Count);
        return assign(_Right_data._Myptr() + _Roff, _Count);
    }

#if _HAS_CXX17
    template <class _StringViewIsh, class = _Is_string_view_ish<_StringViewIsh>>
    basic_string& assign(const _StringViewIsh& _Right) { // assign _Right
        const basic_string_view<_Elem, _Traits> _As_view = _Right;
        return assign(_As_view.data(), _Convert_size<size_type>(_As_view.size()));
    }

    template <class _StringViewIsh, class = _Is_string_view_ish<_StringViewIsh>>
    basic_string& assign(const _StringViewIsh& _Right, const size_type _Roff,
        const size_type _Count = npos) { // assign _Right [_Roff, _Roff + _Count)
        basic_string_view<_Elem, _Traits> _As_view = _Right;
        return assign(_As_view.substr(_Roff, _Count));
    }
#endif // _HAS_CXX17

    basic_string& assign(_In_reads_(_Count) const _Elem* const _Ptr, _CRT_GUARDOVERFLOW const size_type _Count) {
        // assign [_Ptr, _Ptr + _Count)
        auto& _My_data = _Get_data();
        if (_Count <= _My_data._Myres) {
            _Elem* const _Old_ptr = _My_data._Myptr();
            _My_data._Mysize      = _Count;
            _Traits::move(_Old_ptr, _Ptr, _Count);
            _Traits::assign(_Old_ptr[_Count], _Elem());
            return *this;
        }

        return _Reallocate_for(_Count,
            [](_Elem* const _New_ptr, const size_type _Count, const _Elem* const _Ptr) {
                _Traits::copy(_New_ptr, _Ptr, _Count);
                _Traits::assign(_New_ptr[_Count], _Elem());
            },
            _Ptr);
    }

    basic_string& assign(_In_z_ const _Elem* const _Ptr) { // assign [_Ptr, <null>)
        return assign(_Ptr, _Convert_size<size_type>(_Traits::length(_Ptr)));
    }

    basic_string& assign(_CRT_GUARDOVERFLOW const size_type _Count, const _Elem _Ch) { // assign _Count * _Ch
        auto& _My_data = _Get_data();
        if (_Count <= _My_data._Myres) {
            _Elem* const _Old_ptr = _My_data._Myptr();
            _My_data._Mysize      = _Count;
            _Traits::assign(_Old_ptr, _Count, _Ch);
            _Traits::assign(_Old_ptr[_Count], _Elem());
            return *this;
        }

        return _Reallocate_for(_Count,
            [](_Elem* const _New_ptr, const size_type _Count, const _Elem _Ch) {
                _Traits::assign(_New_ptr, _Count, _Ch);
                _Traits::assign(_New_ptr[_Count], _Elem());
            },
            _Ch);
    }

    template <class _Iter, class = enable_if_t<_Is_iterator_v<_Iter>>>
    basic_string& assign(const _Iter _First, const _Iter _Last) { // assign [_First, _Last), input iterators
        return replace(begin(), end(), _First, _Last);
    }

    basic_string& insert(const size_type _Off, const basic_string& _Right) { // insert _Right at _Off
        auto& _Right_data = _Right._Get_data();
        return insert(_Off, _Right_data._Myptr(), _Right_data._Mysize);
    }

    basic_string& insert(const size_type _Off, const basic_string& _Right, const size_type _Roff,
        size_type _Count = npos) { // insert _Right [_Roff, _Roff + _Count) at _Off
        auto& _Right_data = _Right._Get_data();
        _Right_data._Check_offset(_Roff);
        _Count = _Right_data._Clamp_suffix_size(_Roff, _Count);
        return insert(_Off, _Right_data._Myptr() + _Roff, _Count);
    }

#if _HAS_CXX17
    template <class _StringViewIsh, class = _Is_string_view_ish<_StringViewIsh>>
    basic_string& insert(const size_type _Off, const _StringViewIsh& _Right) { // insert _Right at _Off
        const basic_string_view<_Elem, _Traits> _As_view = _Right;
        return insert(_Off, _As_view.data(), _Convert_size<size_type>(_As_view.size()));
    }

    template <class _StringViewIsh, class = _Is_string_view_ish<_StringViewIsh>>
    basic_string& insert(const size_type _Off, const _StringViewIsh& _Right, const size_type _Roff,
        const size_type _Count = npos) { // insert _Right [_Roff, _Roff + _Count) at _Off
        basic_string_view<_Elem, _Traits> _As_view = _Right;
        return insert(_Off, _As_view.substr(_Roff, _Count));
    }
#endif // _HAS_CXX17

    basic_string& insert(
        const size_type _Off, _In_reads_(_Count) const _Elem* const _Ptr, _CRT_GUARDOVERFLOW const size_type _Count) {
        // insert [_Ptr, _Ptr + _Count) at _Off
        auto& _My_data = _Get_data();
        _My_data._Check_offset(_Off);
        const size_type _Old_size = _My_data._Mysize;
        if (_Count <= _My_data._Myres - _Old_size) {
            _My_data._Mysize        = _Old_size + _Count;
            _Elem* const _Old_ptr   = _My_data._Myptr();
            _Elem* const _Insert_at = _Old_ptr + _Off;
            // the range [_Ptr, _Ptr + _Ptr_shifted_after) is left alone by moving the suffix out,
            // while the range [_Ptr + _Ptr_shifted_after, _Ptr + _Count) shifts down by _Count
            size_type _Ptr_shifted_after;
            if (_Ptr + _Count <= _Insert_at
                || _Ptr > _Old_ptr + _Old_size) { // inserted content is before the shifted region, or does not alias
                _Ptr_shifted_after = _Count; // none of _Ptr's data shifts
            } else if (_Insert_at <= _Ptr) { // all of [_Ptr, _Ptr + _Count) shifts
                _Ptr_shifted_after = 0;
            } else { // [_Ptr, _Ptr + _Count) contains _Insert_at, so only the part after _Insert_at shifts
                _Ptr_shifted_after = static_cast<size_type>(_Insert_at - _Ptr);
            }

            _Traits::move(_Insert_at + _Count, _Insert_at, _Old_size - _Off + 1); // move suffix + null down
            _Traits::copy(_Insert_at, _Ptr, _Ptr_shifted_after);
            _Traits::copy(
                _Insert_at + _Ptr_shifted_after, _Ptr + _Count + _Ptr_shifted_after, _Count - _Ptr_shifted_after);
            return *this;
        }

        return _Reallocate_grow_by(_Count,
            [](_Elem* const _New_ptr, const _Elem* const _Old_ptr, const size_type _Old_size, const size_type _Off,
                const _Elem* const _Ptr, const size_type _Count) {
                _Traits::copy(_New_ptr, _Old_ptr, _Off);
                _Traits::copy(_New_ptr + _Off, _Ptr, _Count);
                _Traits::copy(_New_ptr + _Off + _Count, _Old_ptr + _Off, _Old_size - _Off + 1);
            },
            _Off, _Ptr, _Count);
    }

    basic_string& insert(const size_type _Off, _In_z_ const _Elem* const _Ptr) { // insert [_Ptr, <null>) at _Off
        return insert(_Off, _Ptr, _Convert_size<size_type>(_Traits::length(_Ptr)));
    }

    basic_string& insert(const size_type _Off, _CRT_GUARDOVERFLOW const size_type _Count, const _Elem _Ch) {
        // insert _Count * _Ch at _Off
        auto& _My_data = _Get_data();
        _My_data._Check_offset(_Off);
        const size_type _Old_size = _My_data._Mysize;
        if (_Count <= _My_data._Myres - _Old_size) {
            _My_data._Mysize        = _Old_size + _Count;
            _Elem* const _Old_ptr   = _My_data._Myptr();
            _Elem* const _Insert_at = _Old_ptr + _Off;
            _Traits::move(_Insert_at + _Count, _Insert_at, _Old_size - _Off + 1); // move suffix + null down
            _Traits::assign(_Insert_at, _Count, _Ch); // fill hole
            return *this;
        }

        return _Reallocate_grow_by(_Count,
            [](_Elem* const _New_ptr, const _Elem* const _Old_ptr, const size_type _Old_size, const size_type _Off,
                const size_type _Count, const _Elem _Ch) {
                _Traits::copy(_New_ptr, _Old_ptr, _Off);
                _Traits::assign(_New_ptr + _Off, _Count, _Ch);
                _Traits::copy(_New_ptr + _Off + _Count, _Old_ptr + _Off, _Old_size - _Off + 1);
            },
            _Off, _Count, _Ch);
    }

    iterator insert(const const_iterator _Where, const _Elem _Ch) { // insert _Ch at _Where
        const difference_type _Off = _Where - begin();
        insert(static_cast<size_type>(_Off), 1, _Ch);
        return begin() + _Off;
    }

    iterator insert(const const_iterator _Where, _CRT_GUARDOVERFLOW const size_type _Count, const _Elem _Ch) {
        // insert _Count * _Elem at _Where
        const difference_type _Off = _Where - begin();
        insert(static_cast<size_type>(_Off), _Count, _Ch);
        return begin() + _Off;
    }

    template <class _Iter, class = enable_if_t<_Is_iterator_v<_Iter>>>
    iterator insert(const const_iterator _Where, const _Iter _First, const _Iter _Last) {
        // insert [_First, _Last) at _Where, input iterators
        const difference_type _Off = _Where - begin();
        replace(_Where, _Where, _First, _Last);
        return begin() + _Off;
    }

    basic_string& erase(const size_type _Off = 0) { // erase elements [_Off, ...)
        auto& _My_data = _Get_data();
        _My_data._Check_offset(_Off);
        _Eos(_Off);
        return *this;
    }

    basic_string& erase(const size_type _Off, size_type _Count) { // erase elements [_Off, _Off + _Count)
        auto& _My_data = _Get_data();
        _My_data._Check_offset(_Off);
        _Count                    = _My_data._Clamp_suffix_size(_Off, _Count);
        const size_type _Old_size = _My_data._Mysize;
        _Elem* const _My_ptr      = _My_data._Myptr();
        _Elem* const _Erase_at    = _My_ptr + _Off;
        const size_type _New_size = _Old_size - _Count;
        _My_data._Mysize          = _New_size;
        _Traits::move(_Erase_at, _Erase_at + _Count, _New_size - _Off + 1); // move suffix + null up
        return *this;
    }

    iterator erase(const const_iterator _Where) { // erase element at _Where
        const difference_type _Off = _Where - begin();
        erase(static_cast<size_type>(_Off), 1);
        return begin() + _Off;
    }

    iterator erase(const const_iterator _First, const const_iterator _Last) { // erase substring [_First, _Last)
        _Adl_verify_range(_First, _Last);
        const difference_type _Off = _First - begin();
        erase(static_cast<size_type>(_Off), static_cast<size_type>(_Last - _First));
        return begin() + _Off;
    }

    void clear() noexcept { // erase all
        _Eos(0);
    }

    basic_string& replace(const size_type _Off, const size_type _N0,
        const basic_string& _Right) { // replace [_Off, _Off + _N0) with _Right
        auto& _Right_data = _Right._Get_data();
        return replace(_Off, _N0, _Right_data._Myptr(), _Right_data._Mysize);
    }

    basic_string& replace(const size_type _Off, size_type _N0, const basic_string& _Right, const size_type _Roff,
        size_type _Count = npos) { // replace [_Off, _Off + _N0) with _Right [_Roff, _Roff + _Count)
        auto& _Right_data = _Right._Get_data();
        _Right_data._Check_offset(_Roff);
        _Count = _Right_data._Clamp_suffix_size(_Roff, _Count);
        return replace(_Off, _N0, _Right_data._Myptr() + _Roff, _Count);
    }

#if _HAS_CXX17
    template <class _StringViewIsh, class = _Is_string_view_ish<_StringViewIsh>>
    basic_string& replace(const size_type _Off, const size_type _N0, const _StringViewIsh& _Right) {
        // replace [_Off, _Off + _N0) with _Right
        basic_string_view<_Elem, _Traits> _As_view = _Right;
        return replace(_Off, _N0, _As_view.data(), _Convert_size<size_type>(_As_view.size()));
    }

    template <class _StringViewIsh, class = _Is_string_view_ish<_StringViewIsh>>
    basic_string& replace(const size_type _Off, const size_type _N0, const _StringViewIsh& _Right,
        const size_type _Roff, const size_type _Count = npos) {
        // replace [_Off, _Off + _N0) with _Right [_Roff, _Roff + _Count)
        basic_string_view<_Elem, _Traits> _As_view = _Right;
        return replace(_Off, _N0, _As_view.substr(_Roff, _Count));
    }
#endif // _HAS_CXX17

    basic_string& replace(
        const size_type _Off, size_type _N0, _In_reads_(_Count) const _Elem* const _Ptr, const size_type _Count) {
        // replace [_Off, _Off + _N0) with [_Ptr, _Ptr + _Count)
        auto& _My_data = _Get_data();
        _My_data._Check_offset(_Off);
        _N0 = _My_data._Clamp_suffix_size(_Off, _N0);
        if (_N0 == _Count) { // size doesn't change, so a single move does the trick
            _Traits::move(_My_data._Myptr() + _Off, _Ptr, _Count);
            return *this;
        }

        const size_type _Old_size    = _My_data._Mysize;
        const size_type _Suffix_size = _Old_size - _N0 - _Off + 1;
        if (_Count < _N0) { // suffix shifts backwards; we don't have to move anything out of the way
            _My_data._Mysize        = _Old_size - (_N0 - _Count);
            _Elem* const _Old_ptr   = _My_data._Myptr();
            _Elem* const _Insert_at = _Old_ptr + _Off;
            _Traits::move(_Insert_at, _Ptr, _Count);
            _Traits::move(_Insert_at + _Count, _Insert_at + _N0, _Suffix_size);
            return *this;
        }

        const size_type _Growth = static_cast<size_type>(_Count - _N0);
        if (_Growth <= _My_data._Myres - _Old_size) { // growth fits
            _My_data._Mysize        = _Old_size + _Growth;
            _Elem* const _Old_ptr   = _My_data._Myptr();
            _Elem* const _Insert_at = _Old_ptr + _Off;
            _Elem* const _Suffix_at = _Insert_at + _N0;

            size_type _Ptr_shifted_after; // see rationale in insert
            if (_Ptr + _Count <= _Insert_at || _Ptr > _Old_ptr + _Old_size) {
                _Ptr_shifted_after = _Count;
            } else if (_Suffix_at <= _Ptr) {
                _Ptr_shifted_after = 0;
            } else {
                _Ptr_shifted_after = static_cast<size_type>(_Suffix_at - _Ptr);
            }

            _Traits::move(_Suffix_at + _Growth, _Suffix_at, _Suffix_size);
            // next case must be move, in case _Ptr begins before _Insert_at and contains part of the hole;
            // this case doesn't occur in insert because the new content must come from outside the removed
            // content there (because in insert there is no removed content)
            _Traits::move(_Insert_at, _Ptr, _Ptr_shifted_after);
            // the next case can be copy, because it comes from the chunk moved out of the way in the
            // first move, and the hole we're filling can't alias the chunk we moved out of the way
            _Traits::copy(
                _Insert_at + _Ptr_shifted_after, _Ptr + _Growth + _Ptr_shifted_after, _Count - _Ptr_shifted_after);
            return *this;
        }

        return _Reallocate_grow_by(_Growth,
            [](_Elem* const _New_ptr, const _Elem* const _Old_ptr, const size_type _Old_size, const size_type _Off,
                const size_type _N0, const _Elem* const _Ptr, const size_type _Count) {
                _Traits::copy(_New_ptr, _Old_ptr, _Off);
                _Traits::copy(_New_ptr + _Off, _Ptr, _Count);
                _Traits::copy(_New_ptr + _Off + _Count, _Old_ptr + _Off + _N0, _Old_size - _N0 - _Off + 1);
            },
            _Off, _N0, _Ptr, _Count);
    }

    basic_string& replace(const size_type _Off, const size_type _N0,
        _In_z_ const _Elem* const _Ptr) { // replace [_Off, _Off + _N0) with [_Ptr, <null>)
        return replace(_Off, _N0, _Ptr, _Convert_size<size_type>(_Traits::length(_Ptr)));
    }

    basic_string& replace(const size_type _Off, size_type _N0, const size_type _Count,
        const _Elem _Ch) { // replace [_Off, _Off + _N0) with _Count * _Ch
        auto& _My_data = _Get_data();
        _My_data._Check_offset(_Off);
        _N0 = _My_data._Clamp_suffix_size(_Off, _N0);
        if (_Count == _N0) {
            _Traits::assign(_My_data._Myptr() + _Off, _Count, _Ch);
            return *this;
        }

        const size_type _Old_size = _My_data._Mysize;
        if (_Count < _N0
            || _Count - _N0 <= _My_data._Myres - _Old_size) { // either we are shrinking, or the growth fits
            _My_data._Mysize = _Old_size + _Count - _N0; // may temporarily overflow;
                                                         // OK because size_type must be unsigned
            _Elem* const _Old_ptr   = _My_data._Myptr();
            _Elem* const _Insert_at = _Old_ptr + _Off;
            _Traits::move(_Insert_at + _Count, _Insert_at + _N0, _Old_size - _N0 - _Off + 1);
            _Traits::assign(_Insert_at, _Count, _Ch);
            return *this;
        }

        return _Reallocate_grow_by(_Count - _N0,
            [](_Elem* const _New_ptr, const _Elem* const _Old_ptr, const size_type _Old_size, const size_type _Off,
                const size_type _N0, const size_type _Count, const _Elem _Ch) {
                _Traits::copy(_New_ptr, _Old_ptr, _Off);
                _Traits::assign(_New_ptr + _Off, _Count, _Ch);
                _Traits::copy(_New_ptr + _Off + _Count, _Old_ptr + _Off + _N0, _Old_size - _N0 - _Off + 1);
            },
            _Off, _N0, _Count, _Ch);
    }

    basic_string& replace(const const_iterator _First, const const_iterator _Last,
        const basic_string& _Right) { // replace [_First, _Last) with _Right
        return replace(static_cast<size_type>(_First - begin()), static_cast<size_type>(_Last - _First), _Right);
    }

#if _HAS_CXX17
    template <class _StringViewIsh, class = _Is_string_view_ish<_StringViewIsh>>
    basic_string& replace(const const_iterator _First, const const_iterator _Last,
        const _StringViewIsh& _Right) { // replace [_First, _Last) with _Right
        return replace(static_cast<size_type>(_First - begin()), static_cast<size_type>(_Last - _First), _Right);
    }
#endif // _HAS_CXX17

    basic_string& replace(const const_iterator _First, const const_iterator _Last,
        _In_reads_(_Count) const _Elem* const _Ptr,
        const size_type _Count) { // replace [_First, _Last) with [_Ptr, _Ptr + _Count)
        return replace(static_cast<size_type>(_First - begin()), static_cast<size_type>(_Last - _First), _Ptr, _Count);
    }

    basic_string& replace(const const_iterator _First, const const_iterator _Last,
        _In_z_ const _Elem* const _Ptr) { // replace [_First, _Last) with [_Ptr, <null>)
        return replace(static_cast<size_type>(_First - begin()), static_cast<size_type>(_Last - _First), _Ptr);
    }

    basic_string& replace(const const_iterator _First, const const_iterator _Last, const size_type _Count,
        const _Elem _Ch) { // replace [_First, _Last) with _Count * _Ch
        return replace(static_cast<size_type>(_First - begin()), static_cast<size_type>(_Last - _First), _Count, _Ch);
    }

    template <class _Iter>
    basic_string& _Replace_range(
        const const_iterator _First, const const_iterator _Last, const _Iter _First2, const _Iter _Last2, false_type) {
        // replace [_First, _Last) with [_First2, _Last2), input iterators
        const basic_string _Right(_First2, _Last2, get_allocator());
        replace(_First, _Last, _Right);
        return *this;
    }

    template <class _Ptr>
    basic_string& _Replace_range(
        const const_iterator _First, const const_iterator _Last, const _Ptr _First2, const _Ptr _Last2, true_type) {
        // replace [_First, _Last) with [_First2, _Last2), pointers
        return replace(static_cast<size_type>(_First - cbegin()), static_cast<size_type>(_Last - _First), _First2,
            static_cast<size_type>(_Last2 - _First2));
    }

    template <class _Iter, class = enable_if_t<_Is_iterator_v<_Iter>>>
    basic_string& replace(
        const const_iterator _First, const const_iterator _Last, const _Iter _First2, const _Iter _Last2) {
        // replace [_First, _Last) with [_First2, _Last2), input iterators
        _Adl_verify_range(_First2, _Last2);
        const auto _UFirst2 = _Get_unwrapped(_First2);
        const auto _ULast2  = _Get_unwrapped(_Last2);
        return _Replace_range(_First, _Last, _UFirst2, _ULast2, _Is_elem_cptr<decltype(_UFirst2)>());
    }

    _NODISCARD iterator begin() noexcept { // return iterator for beginning of mutable sequence
        auto _My_data = _STD addressof(_Get_data());
        return iterator(_Refancy<pointer>(_My_data->_Myptr()), _My_data);
    }

    _NODISCARD const_iterator begin() const noexcept { // return iterator for beginning of immutable sequence
        auto _My_data = _STD addressof(_Get_data());
        return const_iterator(_Refancy<const_pointer>(_My_data->_Myptr()), _My_data);
    }

    _NODISCARD iterator end() noexcept { // return iterator for end of mutable sequence
        auto _My_data = _STD addressof(_Get_data());
        return iterator(
            _Refancy<pointer>(_My_data->_Myptr()) + static_cast<difference_type>(_My_data->_Mysize), _My_data);
    }

    _NODISCARD const_iterator end() const noexcept { // return iterator for end of immutable sequence
        auto _My_data = _STD addressof(_Get_data());
        return const_iterator(
            _Refancy<const_pointer>(_My_data->_Myptr()) + static_cast<difference_type>(_My_data->_Mysize), _My_data);
    }

    _Elem* _Unchecked_begin() noexcept { // return pointer for beginning of mutable sequence
        return _Get_data()._Myptr();
    }

    const _Elem* _Unchecked_begin() const noexcept { // return pointer for beginning of immutable sequence
        return _Get_data()._Myptr();
    }

    _Elem* _Unchecked_end() noexcept { // return pointer for end of mutable sequence
        auto& _My_data = _Get_data();
        return _My_data._Myptr() + _My_data._Mysize;
    }

    const _Elem* _Unchecked_end() const noexcept { // return pointer for end of immutable sequence
        const auto& _My_data = _Get_data();
        return _My_data._Myptr() + _My_data._Mysize;
    }

    _NODISCARD reverse_iterator rbegin() noexcept { // return iterator for beginning of reversed mutable sequence
        return reverse_iterator(end());
    }

    _NODISCARD const_reverse_iterator rbegin() const
        noexcept { // return iterator for beginning of reversed immutable sequence
        return const_reverse_iterator(end());
    }

    _NODISCARD reverse_iterator rend() noexcept { // return iterator for end of reversed mutable sequence
        return reverse_iterator(begin());
    }

    _NODISCARD const_reverse_iterator rend() const noexcept { // return iterator for end of reversed immutable sequence
        return const_reverse_iterator(begin());
    }

    _NODISCARD const_iterator cbegin() const noexcept { // return iterator for beginning of immutable sequence
        return begin();
    }

    _NODISCARD const_iterator cend() const noexcept { // return iterator for end of immutable sequence
        return end();
    }

    _NODISCARD const_reverse_iterator crbegin() const
        noexcept { // return iterator for beginning of reversed immutable sequence
        return rbegin();
    }

    _NODISCARD const_reverse_iterator crend() const noexcept { // return iterator for end of reversed immutable sequence
        return rend();
    }

    void shrink_to_fit() { // reduce capacity
        auto& _My_data = _Get_data();
        if (!_My_data._Large_string_engaged()) { // can't shrink from small mode
            return;
        }

        if (_My_data._Mysize < _BUF_SIZE) {
            _Become_small();
            return;
        }

        const size_type _Target_capacity = _Min_value(_My_data._Mysize | _ALLOC_MASK, max_size());
        if (_Target_capacity < _My_data._Myres) { // worth shrinking, do it
            auto& _Al              = _Getal();
            const pointer _New_ptr = _Al.allocate(_Target_capacity + 1); // throws
            _Orphan_all();
            _Traits::copy(_Unfancy(_New_ptr), _Unfancy(_My_data._Bx._Ptr), _My_data._Mysize + 1);
            _Al.deallocate(_My_data._Bx._Ptr, _My_data._Myres + 1);
            _My_data._Bx._Ptr = _New_ptr;
            _My_data._Myres   = _Target_capacity;
        }
    }

    _NODISCARD reference at(const size_type _Off) { // subscript mutable sequence with checking
        auto& _My_data = _Get_data();
        _My_data._Check_offset_exclusive(_Off);
        return _My_data._Myptr()[_Off];
    }

    _NODISCARD const_reference at(const size_type _Off) const { // subscript immutable sequence with checking
        auto& _My_data = _Get_data();
        _My_data._Check_offset_exclusive(_Off);
        return _My_data._Myptr()[_Off];
    }

    _NODISCARD reference operator[](const size_type _Off) { // subscript mutable sequence
        auto& _My_data = _Get_data();
#if _ITERATOR_DEBUG_LEVEL >= 1
        _STL_VERIFY(_Off <= _My_data._Mysize, "string subscript out of range");
#endif // _ITERATOR_DEBUG_LEVEL >= 1
        return _My_data._Myptr()[_Off];
    }

    _NODISCARD const_reference operator[](const size_type _Off) const { // subscript immutable sequence
        auto& _My_data = _Get_data();
#if _ITERATOR_DEBUG_LEVEL >= 1
        _STL_VERIFY(_Off <= _My_data._Mysize, "string subscript out of range");
#endif // _ITERATOR_DEBUG_LEVEL >= 1
        return _My_data._Myptr()[_Off];
    }

#if _HAS_CXX17
    /* implicit */ operator basic_string_view<_Elem, _Traits>() const
        noexcept { // return a string_view around *this's character-type sequence
        auto& _My_data = _Get_data();
        return basic_string_view<_Elem, _Traits>(_My_data._Myptr(), _My_data._Mysize);
    }
#endif // _HAS_CXX17

    void push_back(const _Elem _Ch) { // insert element at end
        auto& _My_data            = _Get_data();
        const size_type _Old_size = _My_data._Mysize;
        if (_Old_size < _My_data._Myres) {
            _My_data._Mysize  = _Old_size + 1;
            _Elem* const _Ptr = _My_data._Myptr();
            _Traits::assign(_Ptr[_Old_size], _Ch);
            _Traits::assign(_Ptr[_Old_size + 1], _Elem());
            return;
        }

        _Reallocate_grow_by(1,
            [](_Elem* const _New_ptr, const _Elem* const _Old_ptr, const size_type _Old_size, const _Elem _Ch) {
                _Traits::copy(_New_ptr, _Old_ptr, _Old_size);
                _Traits::assign(_New_ptr[_Old_size], _Ch);
                _Traits::assign(_New_ptr[_Old_size + 1], _Elem());
            },
            _Ch);
    }

    void pop_back() { // erase element at end
        auto& _My_data            = _Get_data();
        const size_type _Old_size = _My_data._Mysize;
#if _ITERATOR_DEBUG_LEVEL >= 1
        _STL_VERIFY(_Old_size != 0, "invalid to pop_back empty string");
#endif // _ITERATOR_DEBUG_LEVEL >= 1
        _Eos(_Old_size - 1);
    }

    _NODISCARD reference front() { // return first element of mutable sequence
        return *begin();
    }

    _NODISCARD const_reference front() const { // return first element of immutable sequence
        return *begin();
    }

    _NODISCARD reference back() { // return last element of mutable sequence
        return *(end() - 1);
    }

    _NODISCARD const_reference back() const { // return last element of immutable sequence
        return *(end() - 1);
    }

    _NODISCARD _Ret_z_ const _Elem* c_str() const noexcept { // return pointer to null-terminated immutable array
        return _Get_data()._Myptr();
    }

    _NODISCARD _Ret_z_ const _Elem* data() const noexcept { // return pointer to immutable array
        return _Get_data()._Myptr();
    }

#if _HAS_CXX17
    _NODISCARD _Ret_z_ _Elem* data() noexcept { // return pointer to mutable array
        return _Get_data()._Myptr();
    }
#endif // _HAS_CXX17

    _NODISCARD size_type length() const noexcept { // return length of sequence
        return _Get_data()._Mysize;
    }

    _NODISCARD size_type size() const noexcept { // return length of sequence
        return _Get_data()._Mysize;
    }

    _NODISCARD size_type max_size() const noexcept { // return maximum possible length of sequence
        const size_type _Alloc_max   = _Alty_traits::max_size(_Getal());
        const size_type _Storage_max = // can always store small string
            _Max_value(_Alloc_max, static_cast<size_type>(_BUF_SIZE));
        return _Min_value(static_cast<size_type>((numeric_limits<difference_type>::max)()),
            _Storage_max - 1 // -1 is for null terminator and/or npos
        );
    }

    void resize(_CRT_GUARDOVERFLOW const size_type _Newsize, const _Elem _Ch = _Elem()) {
        // determine new length, padding with _Ch elements as needed
        const size_type _Old_size = size();
        if (_Newsize <= _Old_size) {
            _Eos(_Newsize);
        } else {
            append(_Newsize - _Old_size, _Ch);
        }
    }

    _NODISCARD size_type capacity() const noexcept { // return current length of allocated storage
        return _Get_data()._Myres;
    }

    void reserve(_CRT_GUARDOVERFLOW const size_type _Newcap = 0) { // determine new minimum length of allocated storage
        auto& _My_data = _Get_data();
        if (_My_data._Mysize > _Newcap) { // requested capacity is not large enough for current size, ignore
            return; // nothing to do
        }

        if (_My_data._Myres == _Newcap) { // we're already at the requested capacity
            return; // nothing to do
        }

        if (_My_data._Myres < _Newcap) { // reallocate to grow
            const size_type _Old_size = _My_data._Mysize;
            _Reallocate_grow_by(
                _Newcap - _Old_size, [](_Elem* const _New_ptr, const _Elem* const _Old_ptr, const size_type _Old_size) {
                    _Traits::copy(_New_ptr, _Old_ptr, _Old_size + 1);
                });

            _My_data._Mysize = _Old_size;
            return;
        }

        if (_BUF_SIZE > _Newcap
            && _My_data._Large_string_engaged()) { // deallocate everything; switch back to "small" mode
            _Become_small();
            return;
        }

        // ignore requests to reserve to [_BUF_SIZE, _Myres)
    }

    _NODISCARD bool empty() const noexcept { // test if sequence is empty
        return size() == 0;
    }

    size_type copy(_Out_writes_(_Count) _Elem* const _Ptr, size_type _Count, const size_type _Off = 0) const {
        // copy [_Off, _Off + _Count) to [_Ptr, _Ptr + _Count)
        auto& _My_data = _Get_data();
        _My_data._Check_offset(_Off);
        _Count = _My_data._Clamp_suffix_size(_Off, _Count);
        _Traits::copy(_Ptr, _My_data._Myptr() + _Off, _Count);
        return _Count;
    }

    _Pre_satisfies_(_Dest_size >= _Count) size_type _Copy_s(_Out_writes_all_(_Dest_size) _Elem* const _Dest,
        const size_type _Dest_size, size_type _Count, const size_type _Off = 0) const {
        // copy [_Off, _Off + _Count) to [_Dest, _Dest + _Dest_size)
        auto& _My_data = _Get_data();
        _My_data._Check_offset(_Off);
        _Count = _My_data._Clamp_suffix_size(_Off, _Count);
        _Traits::_Copy_s(_Dest, _Dest_size, _My_data._Myptr() + _Off, _Count);
        return _Count;
    }

    void _Swap_data(basic_string& _Right, true_type) {
        // exchange _Get_data() with _Right._Get_data(), memcpy optimization
        const auto _My_data_mem = reinterpret_cast<unsigned char*>(_STD addressof(_Get_data())) + _Memcpy_move_offset;
        const auto _Right_data_mem =
            reinterpret_cast<unsigned char*>(_STD addressof(_Right._Get_data())) + _Memcpy_move_offset;
        unsigned char _Temp_mem[_Memcpy_move_size];
        _CSTD memcpy(_Temp_mem, _My_data_mem, _Memcpy_move_size);
        _CSTD memcpy(_My_data_mem, _Right_data_mem, _Memcpy_move_size);
        _CSTD memcpy(_Right_data_mem, _Temp_mem, _Memcpy_move_size);
    }

    void _Swap_bx_large_with_small(_Scary_val& _Starts_large, _Scary_val& _Starts_small) {
        // exchange a string in large mode with one in small mode
        const pointer _Ptr = _Starts_large._Bx._Ptr;
        auto& _Al          = _Getal();
        _Alty_traits::destroy(_Al, _STD addressof(_Starts_large._Bx._Ptr));
        _Traits::copy(_Starts_large._Bx._Buf, _Starts_small._Bx._Buf, _BUF_SIZE);
        _Alty_traits::construct(_Al, _STD addressof(_Starts_small._Bx._Ptr), _Ptr);
    }

    void _Swap_data(basic_string& _Right, false_type) {
        // exchange _Get_data() with _Right._Get_data(), general case
        auto& _My_data          = _Get_data();
        auto& _Right_data       = _Right._Get_data();
        const bool _My_large    = _My_data._Large_string_engaged();
        const bool _Right_large = _Right_data._Large_string_engaged();
        if (_My_large) {
            if (_Right_large) { // swap buffers, iterators preserved
                _Swap_adl(_My_data._Bx._Ptr, _Right_data._Bx._Ptr);
            } else { // swap large with small
                _Swap_bx_large_with_small(_My_data, _Right_data);
            }
        } else {
            if (_Right_large) { // swap small with large
                _Swap_bx_large_with_small(_Right_data, _My_data);
            } else {
                _Elem _Temp_buf[_BUF_SIZE];
                _Traits::copy(_Temp_buf, _My_data._Bx._Buf, _BUF_SIZE);
                _Traits::copy(_My_data._Bx._Buf, _Right_data._Bx._Buf, _BUF_SIZE);
                _Traits::copy(_Right_data._Bx._Buf, _Temp_buf, _BUF_SIZE);
            }
        }

        _STD swap(_My_data._Mysize, _Right_data._Mysize);
        _STD swap(_My_data._Myres, _Right_data._Myres);
    }

    void swap(basic_string& _Right) noexcept { // strengthened
        // exchange contents with _Right
        if (this != _STD addressof(_Right)) { // (maybe) swap allocators, swap control information
            _Pocs(_Getal(), _Right._Getal());

#if _ITERATOR_DEBUG_LEVEL != 0
            auto& _My_data          = _Get_data();
            auto& _Right_data       = _Right._Get_data();
            const bool _My_large    = _My_data._Large_string_engaged();
            const bool _Right_large = _Right_data._Large_string_engaged();
            if (!_My_large) {
                _My_data._Orphan_all();
            }

            if (!_Right_large) {
                _Right_data._Orphan_all();
            }

            if (_My_large || _Right_large) {
                _My_data._Swap_proxy_and_iterators(_Right_data);
            }
#endif // _ITERATOR_DEBUG_LEVEL != 0
        }

        _Swap_data(_Right, _Use_memcpy_move{});
    }

#if _HAS_CXX17
    template <class _StringViewIsh, class = _Is_string_view_ish<_StringViewIsh>>
    _NODISCARD size_type find(
        const _StringViewIsh& _Right, const size_type _Off = 0) const { // look for _Right beginning at or after _Off
        basic_string_view<_Elem, _Traits> _As_view = _Right;
        auto& _My_data                             = _Get_data();
        return static_cast<size_type>(
            _Traits_find<_Traits>(_My_data._Myptr(), _My_data._Mysize, _Off, _As_view.data(), _As_view.size()));
    }
#endif // _HAS_CXX17

    _NODISCARD size_type find(const basic_string& _Right, const size_type _Off = 0) const
        noexcept { // look for _Right beginning at or after _Off
        auto& _My_data    = _Get_data();
        auto& _Right_data = _Right._Get_data();
        return static_cast<size_type>(_Traits_find<_Traits>(
            _My_data._Myptr(), _My_data._Mysize, _Off, _Right_data._Myptr(), _Right_data._Mysize));
    }

    _NODISCARD size_type find(_In_reads_(_Count) const _Elem* const _Ptr, const size_type _Off,
        const size_type _Count) const noexcept { // strengthened
        // look for [_Ptr, _Ptr + _Count) beginning at or after _Off
        auto& _My_data = _Get_data();
        return static_cast<size_type>(_Traits_find<_Traits>(_My_data._Myptr(), _My_data._Mysize, _Off, _Ptr, _Count));
    }

    _NODISCARD size_type find(_In_z_ const _Elem* const _Ptr, const size_type _Off = 0) const noexcept { // strengthened
        // look for [_Ptr, <null>) beginning at or after _Off
        auto& _My_data = _Get_data();
        return static_cast<size_type>(
            _Traits_find<_Traits>(_My_data._Myptr(), _My_data._Mysize, _Off, _Ptr, _Traits::length(_Ptr)));
    }

    _NODISCARD size_type find(const _Elem _Ch, const size_type _Off = 0) const noexcept { // strengthened
        // look for _Ch at or after _Off
        auto& _My_data = _Get_data();
        return static_cast<size_type>(_Traits_find_ch<_Traits>(_My_data._Myptr(), _My_data._Mysize, _Off, _Ch));
    }

#if _HAS_CXX17
    template <class _StringViewIsh, class = _Is_string_view_ish<_StringViewIsh>>
    _NODISCARD size_type rfind(const _StringViewIsh& _Right, const size_type _Off = npos) const {
        // look for _Right beginning before _Off
        basic_string_view<_Elem, _Traits> _As_view = _Right;
        auto& _My_data                             = _Get_data();
        return static_cast<size_type>(
            _Traits_rfind<_Traits>(_My_data._Myptr(), _My_data._Mysize, _Off, _As_view.data(), _As_view.size()));
    }
#endif // _HAS_CXX17

    _NODISCARD size_type rfind(const basic_string& _Right, const size_type _Off = npos) const noexcept {
        // look for _Right beginning before _Off
        auto& _My_data    = _Get_data();
        auto& _Right_data = _Right._Get_data();
        return static_cast<size_type>(_Traits_rfind<_Traits>(
            _My_data._Myptr(), _My_data._Mysize, _Off, _Right_data._Myptr(), _Right_data._Mysize));
    }

    _NODISCARD size_type rfind(_In_reads_(_Count) const _Elem* const _Ptr, const size_type _Off,
        const size_type _Count) const noexcept { // strengthened
        // look for [_Ptr, _Ptr + _Count) beginning before _Off
        auto& _My_data = _Get_data();
        return static_cast<size_type>(_Traits_rfind<_Traits>(_My_data._Myptr(), _My_data._Mysize, _Off, _Ptr, _Count));
    }

    _NODISCARD size_type rfind(_In_z_ const _Elem* const _Ptr, const size_type _Off = npos) const
        noexcept { // strengthened
        // look for [_Ptr, <null>) beginning before _Off
        auto& _My_data = _Get_data();
        return static_cast<size_type>(
            _Traits_rfind<_Traits>(_My_data._Myptr(), _My_data._Mysize, _Off, _Ptr, _Traits::length(_Ptr)));
    }

    _NODISCARD size_type rfind(const _Elem _Ch, const size_type _Off = npos) const noexcept { // strengthened
        // look for _Ch before _Off
        auto& _My_data = _Get_data();
        return static_cast<size_type>(_Traits_rfind_ch<_Traits>(_My_data._Myptr(), _My_data._Mysize, _Off, _Ch));
    }

#if _HAS_CXX17
    template <class _StringViewIsh, class = _Is_string_view_ish<_StringViewIsh>>
    _NODISCARD size_type find_first_of(const _StringViewIsh& _Right, const size_type _Off = 0) const {
        // look for one of _Right at or after _Off
        basic_string_view<_Elem, _Traits> _As_view = _Right;
        auto& _My_data                             = _Get_data();
        return static_cast<size_type>(_Traits_find_first_of<_Traits>(_My_data._Myptr(), _My_data._Mysize, _Off,
            _As_view.data(), _As_view.size(), _Is_specialization<_Traits, char_traits>{}));
    }
#endif // _HAS_CXX17

    _NODISCARD size_type find_first_of(const basic_string& _Right, const size_type _Off = 0) const noexcept {
        // look for one of _Right at or after _Off
        auto& _My_data    = _Get_data();
        auto& _Right_data = _Right._Get_data();
        return static_cast<size_type>(_Traits_find_first_of<_Traits>(_My_data._Myptr(), _My_data._Mysize, _Off,
            _Right_data._Myptr(), _Right_data._Mysize, _Is_specialization<_Traits, char_traits>{}));
    }

    _NODISCARD size_type find_first_of(_In_reads_(_Count) const _Elem* const _Ptr, const size_type _Off,
        const size_type _Count) const noexcept { // strengthened
        // look for one of [_Ptr, _Ptr + _Count) at or after _Off
        auto& _My_data = _Get_data();
        return static_cast<size_type>(_Traits_find_first_of<_Traits>(
            _My_data._Myptr(), _My_data._Mysize, _Off, _Ptr, _Count, _Is_specialization<_Traits, char_traits>{}));
    }

    _NODISCARD size_type find_first_of(_In_z_ const _Elem* const _Ptr, const size_type _Off = 0) const
        noexcept { // strengthened
        // look for one of [_Ptr, <null>) at or after _Off
        auto& _My_data = _Get_data();
        return static_cast<size_type>(_Traits_find_first_of<_Traits>(_My_data._Myptr(), _My_data._Mysize, _Off, _Ptr,
            _Traits::length(_Ptr), _Is_specialization<_Traits, char_traits>{}));
    }

    _NODISCARD size_type find_first_of(const _Elem _Ch, const size_type _Off = 0) const noexcept { // strengthened
        // look for _Ch at or after _Off
        auto& _My_data = _Get_data();
        return static_cast<size_type>(_Traits_find_ch<_Traits>(_My_data._Myptr(), _My_data._Mysize, _Off, _Ch));
    }

#if _HAS_CXX17
    template <class _StringViewIsh, class = _Is_string_view_ish<_StringViewIsh>>
    _NODISCARD size_type find_last_of(const _StringViewIsh& _Right, const size_type _Off = npos) const {
        // look for one of _Right before _Off
        basic_string_view<_Elem, _Traits> _As_view = _Right;
        auto& _My_data                             = _Get_data();
        return static_cast<size_type>(_Traits_find_last_of<_Traits>(_My_data._Myptr(), _My_data._Mysize, _Off,
            _As_view.data(), _As_view.size(), _Is_specialization<_Traits, char_traits>{}));
    }
#endif // _HAS_CXX17

    _NODISCARD size_type find_last_of(const basic_string& _Right, size_type _Off = npos) const noexcept {
        // look for one of _Right before _Off
        auto& _My_data    = _Get_data();
        auto& _Right_data = _Right._Get_data();
        return static_cast<size_type>(_Traits_find_last_of<_Traits>(_My_data._Myptr(), _My_data._Mysize, _Off,
            _Right_data._Myptr(), _Right_data._Mysize, _Is_specialization<_Traits, char_traits>{}));
    }

    _NODISCARD size_type find_last_of(_In_reads_(_Count) const _Elem* const _Ptr, const size_type _Off,
        const size_type _Count) const noexcept { // strengthened
        // look for one of [_Ptr, _Ptr + _Count) before _Off
        auto& _My_data = _Get_data();
        return static_cast<size_type>(_Traits_find_last_of<_Traits>(
            _My_data._Myptr(), _My_data._Mysize, _Off, _Ptr, _Count, _Is_specialization<_Traits, char_traits>{}));
    }

    _NODISCARD size_type find_last_of(_In_z_ const _Elem* const _Ptr, const size_type _Off = npos) const
        noexcept { // strengthened
        // look for one of [_Ptr, <null>) before _Off
        auto& _My_data = _Get_data();
        return static_cast<size_type>(_Traits_find_last_of<_Traits>(_My_data._Myptr(), _My_data._Mysize, _Off, _Ptr,
            _Traits::length(_Ptr), _Is_specialization<_Traits, char_traits>{}));
    }

    _NODISCARD size_type find_last_of(const _Elem _Ch, const size_type _Off = npos) const noexcept { // strengthened
        // look for _Ch before _Off
        auto& _My_data = _Get_data();
        return static_cast<size_type>(_Traits_rfind_ch<_Traits>(_My_data._Myptr(), _My_data._Mysize, _Off, _Ch));
    }

#if _HAS_CXX17
    template <class _StringViewIsh, class = _Is_string_view_ish<_StringViewIsh>>
    _NODISCARD size_type find_first_not_of(const _StringViewIsh& _Right, const size_type _Off = 0) const {
        // look for none of _Right at or after _Off
        basic_string_view<_Elem, _Traits> _As_view = _Right;
        auto& _My_data                             = _Get_data();
        return static_cast<size_type>(_Traits_find_first_not_of<_Traits>(_My_data._Myptr(), _My_data._Mysize, _Off,
            _As_view.data(), _As_view.size(), _Is_specialization<_Traits, char_traits>{}));
    }
#endif // _HAS_CXX17

    _NODISCARD size_type find_first_not_of(const basic_string& _Right, const size_type _Off = 0) const
        noexcept { // look for none of _Right at or after _Off
        auto& _My_data    = _Get_data();
        auto& _Right_data = _Right._Get_data();
        return static_cast<size_type>(_Traits_find_first_not_of<_Traits>(_My_data._Myptr(), _My_data._Mysize, _Off,
            _Right_data._Myptr(), _Right_data._Mysize, _Is_specialization<_Traits, char_traits>{}));
    }

    _NODISCARD size_type find_first_not_of(_In_reads_(_Count) const _Elem* const _Ptr, const size_type _Off,
        const size_type _Count) const noexcept { // strengthened
        // look for none of [_Ptr, _Ptr + _Count) at or after _Off
        auto& _My_data = _Get_data();
        return static_cast<size_type>(_Traits_find_first_not_of<_Traits>(
            _My_data._Myptr(), _My_data._Mysize, _Off, _Ptr, _Count, _Is_specialization<_Traits, char_traits>{}));
    }

    _NODISCARD size_type find_first_not_of(_In_z_ const _Elem* const _Ptr, size_type _Off = 0) const
        noexcept { // strengthened
        // look for one of [_Ptr, <null>) at or after _Off
        auto& _My_data = _Get_data();
        return static_cast<size_type>(_Traits_find_first_not_of<_Traits>(_My_data._Myptr(), _My_data._Mysize, _Off,
            _Ptr, _Traits::length(_Ptr), _Is_specialization<_Traits, char_traits>{}));
    }

    _NODISCARD size_type find_first_not_of(const _Elem _Ch, const size_type _Off = 0) const noexcept { // strengthened
        // look for non _Ch at or after _Off
        auto& _My_data = _Get_data();
        return static_cast<size_type>(_Traits_find_not_ch<_Traits>(_My_data._Myptr(), _My_data._Mysize, _Off, _Ch));
    }

#if _HAS_CXX17
    template <class _StringViewIsh, class = _Is_string_view_ish<_StringViewIsh>>
    _NODISCARD size_type find_last_not_of(const _StringViewIsh& _Right, const size_type _Off = npos) const {
        // look for none of _Right before _Off
        basic_string_view<_Elem, _Traits> _As_view = _Right;
        auto& _My_data                             = _Get_data();
        return static_cast<size_type>(_Traits_find_last_not_of<_Traits>(_My_data._Myptr(), _My_data._Mysize, _Off,
            _As_view.data(), _As_view.size(), _Is_specialization<_Traits, char_traits>{}));
    }
#endif // _HAS_CXX17

    _NODISCARD size_type find_last_not_of(const basic_string& _Right, const size_type _Off = npos) const noexcept {
        // look for none of _Right before _Off
        auto& _My_data    = _Get_data();
        auto& _Right_data = _Right._Get_data();
        return static_cast<size_type>(_Traits_find_last_not_of<_Traits>(_My_data._Myptr(), _My_data._Mysize, _Off,
            _Right_data._Myptr(), _Right_data._Mysize, _Is_specialization<_Traits, char_traits>{}));
    }

    _NODISCARD size_type find_last_not_of(_In_reads_(_Count) const _Elem* const _Ptr, const size_type _Off,
        const size_type _Count) const noexcept { // strengthened
        // look for none of [_Ptr, _Ptr + _Count) before _Off
        auto& _My_data = _Get_data();
        return static_cast<size_type>(_Traits_find_last_not_of<_Traits>(
            _My_data._Myptr(), _My_data._Mysize, _Off, _Ptr, _Count, _Is_specialization<_Traits, char_traits>{}));
    }

    _NODISCARD size_type find_last_not_of(_In_z_ const _Elem* const _Ptr, const size_type _Off = npos) const
        noexcept { // strengthened
        // look for none of [_Ptr, <null>) before _Off
        auto& _My_data = _Get_data();
        return static_cast<size_type>(_Traits_find_last_not_of<_Traits>(_My_data._Myptr(), _My_data._Mysize, _Off, _Ptr,
            _Traits::length(_Ptr), _Is_specialization<_Traits, char_traits>{}));
    }

    _NODISCARD size_type find_last_not_of(const _Elem _Ch, const size_type _Off = npos) const noexcept { // strengthened
        // look for non _Ch before _Off
        auto& _My_data = _Get_data();
        return static_cast<size_type>(_Traits_rfind_not_ch<_Traits>(_My_data._Myptr(), _My_data._Mysize, _Off, _Ch));
    }

#if _HAS_CXX17
    _NODISCARD bool _Starts_with(const basic_string_view<_Elem, _Traits> _Right) const noexcept {
        // test if this instance starts with _Right
        return basic_string_view<_Elem, _Traits>(*this)._Starts_with(_Right);
    }
#endif // _HAS_CXX17

    _NODISCARD basic_string substr(const size_type _Off = 0, const size_type _Count = npos) const {
        // return [_Off, _Off + _Count) as new string
        return basic_string(*this, _Off, _Count, get_allocator());
    }

    bool _Equal(const basic_string& _Right) const noexcept { // compare [0, size()) with _Right for equality
        auto& _My_data    = _Get_data();
        auto& _Right_data = _Right._Get_data();
        return _Traits_equal<_Traits>(_My_data._Myptr(), _My_data._Mysize, _Right_data._Myptr(), _Right_data._Mysize);
    }

    bool _Equal(_In_z_ const _Elem* const _Ptr) const noexcept { // compare [0, size()) with _Ptr for equality
        auto& _My_data = _Get_data();
        return _Traits_equal<_Traits>(_My_data._Myptr(), _My_data._Mysize, _Ptr, _Traits::length(_Ptr));
    }

#if _HAS_CXX17
    template <class _StringViewIsh, class = _Is_string_view_ish<_StringViewIsh>>
    _NODISCARD int compare(const _StringViewIsh& _Right) const { // compare [0, size()) with _Right
        basic_string_view<_Elem, _Traits> _As_view = _Right;
        auto& _My_data                             = _Get_data();
        return _Traits_compare<_Traits>(_My_data._Myptr(), _My_data._Mysize, _As_view.data(), _As_view.size());
    }

    template <class _StringViewIsh, class = _Is_string_view_ish<_StringViewIsh>>
    _NODISCARD int compare(const size_type _Off, const size_type _N0, const _StringViewIsh& _Right) const {
        // compare [_Off, _Off + _N0) with _Right
        basic_string_view<_Elem, _Traits> _As_view = _Right;
        auto& _My_data                             = _Get_data();
        _My_data._Check_offset(_Off);
        return _Traits_compare<_Traits>(
            _My_data._Myptr() + _Off, _My_data._Clamp_suffix_size(_Off, _N0), _As_view.data(), _As_view.size());
    }

    template <class _StringViewIsh, class = _Is_string_view_ish<_StringViewIsh>>
    _NODISCARD int compare(const size_type _Off, const size_type _N0, const _StringViewIsh& _Right,
        const size_type _Roff, const size_type _Count = npos) const {
        // compare [_Off, _Off + _N0) with _Right [_Roff, _Roff + _Count)
        basic_string_view<_Elem, _Traits> _As_view = _Right;
        auto& _My_data                             = _Get_data();
        _My_data._Check_offset(_Off);
        const auto _With_substr = _As_view.substr(_Roff, _Count);
        return _Traits_compare<_Traits>(
            _My_data._Myptr() + _Off, _My_data._Clamp_suffix_size(_Off, _N0), _With_substr.data(), _With_substr.size());
    }
#endif // _HAS_CXX17

    _NODISCARD int compare(const basic_string& _Right) const noexcept { // compare [0, size()) with _Right
        auto& _My_data    = _Get_data();
        auto& _Right_data = _Right._Get_data();
        return _Traits_compare<_Traits>(_My_data._Myptr(), _My_data._Mysize, _Right_data._Myptr(), _Right_data._Mysize);
    }

    _NODISCARD int compare(size_type _Off, size_type _N0, const basic_string& _Right) const {
        // compare [_Off, _Off + _N0) with _Right
        auto& _My_data = _Get_data();
        _My_data._Check_offset(_Off);
        auto& _Right_data = _Right._Get_data();
        return _Traits_compare<_Traits>(_My_data._Myptr() + _Off, _My_data._Clamp_suffix_size(_Off, _N0),
            _Right_data._Myptr(), _Right_data._Mysize);
    }

    _NODISCARD int compare(const size_type _Off, const size_type _N0, const basic_string& _Right, const size_type _Roff,
        const size_type _Count = npos) const { // compare [_Off, _Off + _N0) with _Right [_Roff, _Roff + _Count)
        auto& _My_data    = _Get_data();
        auto& _Right_data = _Right._Get_data();
        _My_data._Check_offset(_Off);
        _Right_data._Check_offset(_Roff);
        return _Traits_compare<_Traits>(_My_data._Myptr() + _Off, _My_data._Clamp_suffix_size(_Off, _N0),
            _Right_data._Myptr() + _Roff, _Right_data._Clamp_suffix_size(_Roff, _Count));
    }

    _NODISCARD int compare(_In_z_ const _Elem* const _Ptr) const noexcept { // strengthened
        // compare [0, size()) with [_Ptr, <null>)
        auto& _My_data = _Get_data();
        return _Traits_compare<_Traits>(_My_data._Myptr(), _My_data._Mysize, _Ptr, _Traits::length(_Ptr));
    }

    _NODISCARD int compare(const size_type _Off, const size_type _N0, _In_z_ const _Elem* const _Ptr) const {
        // compare [_Off, _Off + _N0) with [_Ptr, <null>)
        auto& _My_data = _Get_data();
        _My_data._Check_offset(_Off);
        return _Traits_compare<_Traits>(
            _My_data._Myptr() + _Off, _My_data._Clamp_suffix_size(_Off, _N0), _Ptr, _Traits::length(_Ptr));
    }

    _NODISCARD int compare(const size_type _Off, const size_type _N0, _In_reads_(_Count) const _Elem* const _Ptr,
        const size_type _Count) const { // compare [_Off, _Off + _N0) with [_Ptr, _Ptr + _Count)
        auto& _My_data = _Get_data();
        _My_data._Check_offset(_Off);
        return _Traits_compare<_Traits>(_My_data._Myptr() + _Off, _My_data._Clamp_suffix_size(_Off, _N0), _Ptr, _Count);
    }

#if _HAS_CXX20
    _NODISCARD bool starts_with(const basic_string_view<_Elem, _Traits> _Right) const noexcept {
        // test if this instance starts with _Right
        auto& _My_data = _Get_data();
        return basic_string_view<_Elem, _Traits>(_My_data._Myptr(), _My_data._Mysize).starts_with(_Right);
    }

    _NODISCARD bool starts_with(const _Elem _Right) const noexcept {
        // test if this instance starts with _Right
        auto& _My_data = _Get_data();
        return basic_string_view<_Elem, _Traits>(_My_data._Myptr(), _My_data._Mysize).starts_with(_Right);
    }

    _NODISCARD bool starts_with(const _Elem* const _Right) const noexcept { // strengthened
        // test if this instance starts with _Right
        auto& _My_data = _Get_data();
        return basic_string_view<_Elem, _Traits>(_My_data._Myptr(), _My_data._Mysize).starts_with(_Right);
    }

    _NODISCARD bool ends_with(const basic_string_view<_Elem, _Traits> _Right) const noexcept {
        // test if this instance ends with _Right
        auto& _My_data = _Get_data();
        return basic_string_view<_Elem, _Traits>(_My_data._Myptr(), _My_data._Mysize).ends_with(_Right);
    }

    _NODISCARD bool ends_with(const _Elem _Right) const noexcept {
        // test if this instance ends with _Right
        auto& _My_data = _Get_data();
        return basic_string_view<_Elem, _Traits>(_My_data._Myptr(), _My_data._Mysize).ends_with(_Right);
    }

    _NODISCARD bool ends_with(const _Elem* const _Right) const noexcept { // strengthened
        // test if this instance ends with _Right
        auto& _My_data = _Get_data();
        return basic_string_view<_Elem, _Traits>(_My_data._Myptr(), _My_data._Mysize).ends_with(_Right);
    }
#endif // _HAS_CXX20

    _NODISCARD allocator_type get_allocator() const noexcept { // return allocator object for values
        return static_cast<allocator_type>(_Getal());
    }

private:
    size_type _Calculate_growth(const size_type _Requested) const { // determines the next array size to allocate
        const size_type _Max    = max_size();
        auto& _My_data          = _Get_data();
        const size_type _Masked = _Requested | _ALLOC_MASK;
        if (_Masked > _Max) { // the mask overflows, settle for max_size()
            return _Max;
        }

        const size_type _Old = _My_data._Myres;
        if (_Old > _Max - _Old / 2) { // similarly, geometric overflows
            return _Max;
        }

        return _Max_value(_Masked, _Old + _Old / 2);
    }

    template <class _Fty, class... _ArgTys>
    basic_string& _Reallocate_for(const size_type _New_size, _Fty _Fn, _ArgTys... _Args) {
        // reallocate to store exactly _New_size elements, new buffer prepared by
        // _Fn(_New_ptr, _New_size, _Args...)
        if (_New_size > max_size()) {
            _Xlen(); // result too long
        }

        auto& _My_data                = _Get_data();
        const size_type _Old_capacity = _My_data._Myres;
        const size_type _New_capacity = _Calculate_growth(_New_size);
        auto& _Al                     = _Getal();
        const pointer _New_ptr        = _Al.allocate(_New_capacity + 1); // throws
        _My_data._Orphan_all();
        _My_data._Mysize = _New_size;
        _My_data._Myres  = _New_capacity;
        _Fn(_Unfancy(_New_ptr), _New_size, _Args...);
        if (_BUF_SIZE <= _Old_capacity) {
            _Al.deallocate(_My_data._Bx._Ptr, _Old_capacity + 1);
            _My_data._Bx._Ptr = _New_ptr;
        } else {
            _Alty_traits::construct(_Al, _STD addressof(_My_data._Bx._Ptr), _New_ptr);
        }

        return *this;
    }

    template <class _Fty, class... _ArgTys>
    basic_string& _Reallocate_grow_by(const size_type _Size_increase, _Fty _Fn, _ArgTys... _Args) {
        // reallocate to increase size by _Size_increase elements, new buffer prepared by
        // _Fn(_New_ptr, _Old_ptr, _Old_size, _Args...)
        auto& _My_data            = _Get_data();
        const size_type _Old_size = _My_data._Mysize;
        if (max_size() - _Old_size < _Size_increase) {
            _Xlen(); // result too long
        }

        const size_type _New_size     = _Old_size + _Size_increase;
        const size_type _Old_capacity = _My_data._Myres;
        const size_type _New_capacity = _Calculate_growth(_New_size);
        auto& _Al                     = _Getal();
        const pointer _New_ptr        = _Al.allocate(_New_capacity + 1); // throws
        _My_data._Orphan_all();
        _My_data._Mysize      = _New_size;
        _My_data._Myres       = _New_capacity;
        _Elem* const _Raw_new = _Unfancy(_New_ptr);
        if (_BUF_SIZE <= _Old_capacity) {
            const pointer _Old_ptr = _My_data._Bx._Ptr;
            _Fn(_Raw_new, _Unfancy(_Old_ptr), _Old_size, _Args...);
            _Al.deallocate(_Old_ptr, _Old_capacity + 1);
            _My_data._Bx._Ptr = _New_ptr;
        } else {
            _Fn(_Raw_new, _My_data._Bx._Buf, _Old_size, _Args...);
            _Alty_traits::construct(_Al, _STD addressof(_My_data._Bx._Ptr), _New_ptr);
        }

        return *this;
    }

    void _Become_small() {
        // release any held storage and return to small string mode
        // pre: *this is in large string mode
        // pre: this is small enough to return to small string mode
        auto& _My_data = _Get_data();
        _My_data._Orphan_all();
        const pointer _Ptr = _My_data._Bx._Ptr;
        auto& _Al          = _Getal();
        _Alty_traits::destroy(_Al, _STD addressof(_My_data._Bx._Ptr));
        _Traits::copy(_My_data._Bx._Buf, _Unfancy(_Ptr), _My_data._Mysize + 1);
        _Al.deallocate(_Ptr, _My_data._Myres + 1);
        _My_data._Myres = _BUF_SIZE - 1;
    }

    void _Eos(const size_type _Newsize) { // set new length and null terminator
        auto& _My_data = _Get_data();
        _Traits::assign(_My_data._Myptr()[_My_data._Mysize = _Newsize], _Elem());
    }

    void _Tidy_init() noexcept { // initialize basic_string data members
        auto& _My_data   = _Get_data();
        _My_data._Mysize = 0;
        _My_data._Myres  = _BUF_SIZE - 1;
        // the _Traits::assign is last so the codegen doesn't think the char
        // write can alias this
        _Traits::assign(_My_data._Bx._Buf[0], _Elem());
    }

    void _Tidy_deallocate() noexcept { // initialize buffer, deallocating any storage
        _Orphan_all();
        auto& _My_data = _Get_data();
        if (_My_data._Large_string_engaged()) {
            const pointer _Ptr = _My_data._Bx._Ptr;
            auto& _Al          = _Getal();
            _Alty_traits::destroy(_Al, _STD addressof(_My_data._Bx._Ptr));
            _Al.deallocate(_Ptr, _My_data._Myres + 1);
        }

        _My_data._Mysize = 0;
        _My_data._Myres  = _BUF_SIZE - 1;
        // the _Traits::assign is last so the codegen doesn't think the char
        // write can alias this
        _Traits::assign(_My_data._Bx._Buf[0], _Elem());
    }

    [[noreturn]] static void _Xlen() { // report a length_error
        _Xlength_error("string too long");
    }

public:
    void _Orphan_all() noexcept { // orphan all iterators
        _Get_data()._Orphan_all();
    }

private:
    void _Swap_proxy_and_iterators(basic_string& _Right) { // swap all iterators
        _Get_data()._Swap_proxy_and_iterators(_Right._Get_data());
    }

    _Alty& _Getal() noexcept { // return reference to allocator
        return _Mypair._Get_first();
    }

    const _Alty& _Getal() const noexcept { // return const reference to allocator
        return _Mypair._Get_first();
    }

    _Scary_val& _Get_data() noexcept { // return reference to _Scary_val
        return _Mypair._Myval2;
    }

    const _Scary_val& _Get_data() const noexcept { // return const reference to _Scary_val
        return _Mypair._Myval2;
    }

    _Compressed_pair<_Alty, _Scary_val> _Mypair;
};

#if _HAS_CXX17
template <class _Iter, class _Alloc = allocator<_Iter_value_t<_Iter>>,
    enable_if_t<conjunction_v<_Is_iterator<_Iter>, _Is_allocator<_Alloc>>, int> = 0>
basic_string(_Iter, _Iter, _Alloc = _Alloc())
    ->basic_string<_Iter_value_t<_Iter>, char_traits<_Iter_value_t<_Iter>>, _Alloc>;

template <class _Elem, class _Traits, class _Alloc = allocator<_Elem>,
    enable_if_t<_Is_allocator<_Alloc>::value, int> = 0>
explicit basic_string(basic_string_view<_Elem, _Traits>, const _Alloc& = _Alloc())
    ->basic_string<_Elem, _Traits, _Alloc>;

template <class _Elem, class _Traits, class _Alloc = allocator<_Elem>,
    enable_if_t<_Is_allocator<_Alloc>::value, int> = 0>
basic_string(
    basic_string_view<_Elem, _Traits>, _Guide_size_type_t<_Alloc>, _Guide_size_type_t<_Alloc>, const _Alloc& = _Alloc())
    ->basic_string<_Elem, _Traits, _Alloc>;
#endif // _HAS_CXX17

template <class _Elem, class _Traits, class _Alloc>
inline void swap(basic_string<_Elem, _Traits, _Alloc>& _Left,
    basic_string<_Elem, _Traits, _Alloc>& _Right) noexcept { // strengthened
    // swap _Left and _Right strings
    _Left.swap(_Right);
}

template <class _Elem, class _Traits, class _Alloc>
_NODISCARD inline basic_string<_Elem, _Traits, _Alloc> operator+(const basic_string<_Elem, _Traits, _Alloc>& _Left,
    const basic_string<_Elem, _Traits, _Alloc>& _Right) { // return string + string
    basic_string<_Elem, _Traits, _Alloc> _Ans;
    _Ans.reserve(_Left.size() + _Right.size());
    _Ans += _Left;
    _Ans += _Right;
    return _Ans;
}

template <class _Elem, class _Traits, class _Alloc>
_NODISCARD inline basic_string<_Elem, _Traits, _Alloc> operator+(
    _In_z_ const _Elem* const _Left, const basic_string<_Elem, _Traits, _Alloc>& _Right) { // return NTCTS + string
    using _String_type = basic_string<_Elem, _Traits, _Alloc>;
    using _Size_type   = typename _String_type::size_type;
    _String_type _Ans;
    _Ans.reserve(_Convert_size<_Size_type>(_Traits::length(_Left) + _Right.size()));
    _Ans += _Left;
    _Ans += _Right;
    return _Ans;
}

template <class _Elem, class _Traits, class _Alloc>
_NODISCARD inline basic_string<_Elem, _Traits, _Alloc> operator+(
    const _Elem _Left, const basic_string<_Elem, _Traits, _Alloc>& _Right) { // return character + string
    basic_string<_Elem, _Traits, _Alloc> _Ans;
    _Ans.reserve(1 + _Right.size());
    _Ans += _Left;
    _Ans += _Right;
    return _Ans;
}

template <class _Elem, class _Traits, class _Alloc>
_NODISCARD inline basic_string<_Elem, _Traits, _Alloc> operator+(const basic_string<_Elem, _Traits, _Alloc>& _Left,
    _In_z_ const _Elem* const _Right) { // return string + NTCTS
    using _String_type = basic_string<_Elem, _Traits, _Alloc>;
    using _Size_type   = typename _String_type::size_type;
    _String_type _Ans;
    _Ans.reserve(_Convert_size<_Size_type>(_Left.size() + _Traits::length(_Right)));
    _Ans += _Left;
    _Ans += _Right;
    return _Ans;
}

template <class _Elem, class _Traits, class _Alloc>
_NODISCARD inline basic_string<_Elem, _Traits, _Alloc> operator+(const basic_string<_Elem, _Traits, _Alloc>& _Left,
    const _Elem _Right) { // return string + character
    basic_string<_Elem, _Traits, _Alloc> _Ans;
    _Ans.reserve(_Left.size() + 1);
    _Ans += _Left;
    _Ans += _Right;
    return _Ans;
}

template <class _Elem, class _Traits, class _Alloc>
_NODISCARD inline basic_string<_Elem, _Traits, _Alloc> operator+(const basic_string<_Elem, _Traits, _Alloc>& _Left,
    basic_string<_Elem, _Traits, _Alloc>&& _Right) { // return string + string
    return _STD move(_Right.insert(0, _Left));
}

template <class _Elem, class _Traits, class _Alloc>
_NODISCARD inline basic_string<_Elem, _Traits, _Alloc> operator+(basic_string<_Elem, _Traits, _Alloc>&& _Left,
    const basic_string<_Elem, _Traits, _Alloc>& _Right) { // return string + string
    return _STD move(_Left.append(_Right));
}

template <class _Elem, class _Traits, class _Alloc>
_NODISCARD inline basic_string<_Elem, _Traits, _Alloc> operator+(basic_string<_Elem, _Traits, _Alloc>&& _Left,
    basic_string<_Elem, _Traits, _Alloc>&& _Right) { // return string + string
    if (_Right.size() <= _Left.capacity() - _Left.size() || _Right.capacity() - _Right.size() < _Left.size()) {
        return _STD move(_Left.append(_Right));
    } else {
        return _STD move(_Right.insert(0, _Left));
    }
}

template <class _Elem, class _Traits, class _Alloc>
_NODISCARD inline basic_string<_Elem, _Traits, _Alloc> operator+(
    _In_z_ const _Elem* const _Left, basic_string<_Elem, _Traits, _Alloc>&& _Right) { // return NTCTS + string
    return _STD move(_Right.insert(0, _Left));
}

template <class _Elem, class _Traits, class _Alloc>
_NODISCARD inline basic_string<_Elem, _Traits, _Alloc> operator+(
    const _Elem _Left, basic_string<_Elem, _Traits, _Alloc>&& _Right) { // return character + string
    using size_type = typename allocator_traits<_Alloc>::size_type;
    return _STD move(_Right.insert(static_cast<size_type>(0), static_cast<size_type>(1), _Left));
}

template <class _Elem, class _Traits, class _Alloc>
_NODISCARD inline basic_string<_Elem, _Traits, _Alloc> operator+(basic_string<_Elem, _Traits, _Alloc>&& _Left,
    _In_z_ const _Elem* const _Right) { // return string + NTCTS
    return _STD move(_Left.append(_Right));
}

template <class _Elem, class _Traits, class _Alloc>
_NODISCARD inline basic_string<_Elem, _Traits, _Alloc> operator+(basic_string<_Elem, _Traits, _Alloc>&& _Left,
    const _Elem _Right) { // return string + character
    _Left.push_back(_Right);
    return _STD move(_Left);
}

template <class _Elem, class _Traits, class _Alloc>
_NODISCARD inline bool operator==(const basic_string<_Elem, _Traits, _Alloc>& _Left,
    const basic_string<_Elem, _Traits, _Alloc>& _Right) noexcept { // test for string equality
    return _Left._Equal(_Right);
}

template <class _Elem, class _Traits, class _Alloc>
_NODISCARD inline bool operator==(_In_z_ const _Elem* const _Left,
    const basic_string<_Elem, _Traits, _Alloc>& _Right) { // test for NTCTS vs. string equality
    return _Right._Equal(_Left);
}

template <class _Elem, class _Traits, class _Alloc>
_NODISCARD inline bool operator==(const basic_string<_Elem, _Traits, _Alloc>& _Left,
    _In_z_ const _Elem* const _Right) { // test for string vs. NTCTS equality
    return _Left._Equal(_Right);
}

template <class _Elem, class _Traits, class _Alloc>
_NODISCARD inline bool operator!=(const basic_string<_Elem, _Traits, _Alloc>& _Left,
    const basic_string<_Elem, _Traits, _Alloc>& _Right) noexcept { // test for string inequality
    return !(_Left == _Right);
}

template <class _Elem, class _Traits, class _Alloc>
_NODISCARD inline bool operator!=(_In_z_ const _Elem* const _Left,
    const basic_string<_Elem, _Traits, _Alloc>& _Right) { // test for NTCTS vs. string inequality
    return !(_Left == _Right);
}

template <class _Elem, class _Traits, class _Alloc>
_NODISCARD inline bool operator!=(const basic_string<_Elem, _Traits, _Alloc>& _Left,
    _In_z_ const _Elem* const _Right) { // test for string vs. NTCTS inequality
    return !(_Left == _Right);
}

template <class _Elem, class _Traits, class _Alloc>
_NODISCARD inline bool operator<(const basic_string<_Elem, _Traits, _Alloc>& _Left,
    const basic_string<_Elem, _Traits, _Alloc>& _Right) noexcept { // test if string < string
    return _Left.compare(_Right) < 0;
}

template <class _Elem, class _Traits, class _Alloc>
_NODISCARD inline bool operator<(
    _In_z_ const _Elem* const _Left, const basic_string<_Elem, _Traits, _Alloc>& _Right) { // test if NTCTS < string
    return _Right.compare(_Left) > 0;
}

template <class _Elem, class _Traits, class _Alloc>
_NODISCARD inline bool operator<(const basic_string<_Elem, _Traits, _Alloc>& _Left,
    _In_z_ const _Elem* const _Right) { // test if string < NTCTS
    return _Left.compare(_Right) < 0;
}

template <class _Elem, class _Traits, class _Alloc>
_NODISCARD inline bool operator>(const basic_string<_Elem, _Traits, _Alloc>& _Left,
    const basic_string<_Elem, _Traits, _Alloc>& _Right) noexcept { // test if string > string
    return _Right < _Left;
}

template <class _Elem, class _Traits, class _Alloc>
_NODISCARD inline bool operator>(
    _In_z_ const _Elem* const _Left, const basic_string<_Elem, _Traits, _Alloc>& _Right) { // test if NTCTS > string
    return _Right < _Left;
}

template <class _Elem, class _Traits, class _Alloc>
_NODISCARD inline bool operator>(const basic_string<_Elem, _Traits, _Alloc>& _Left,
    _In_z_ const _Elem* const _Right) { // test if string > NTCTS
    return _Right < _Left;
}

template <class _Elem, class _Traits, class _Alloc>
_NODISCARD inline bool operator<=(const basic_string<_Elem, _Traits, _Alloc>& _Left,
    const basic_string<_Elem, _Traits, _Alloc>& _Right) noexcept { // test if string <= string
    return !(_Right < _Left);
}

template <class _Elem, class _Traits, class _Alloc>
_NODISCARD inline bool operator<=(
    _In_z_ const _Elem* const _Left, const basic_string<_Elem, _Traits, _Alloc>& _Right) { // test if NTCTS <= string
    return !(_Right < _Left);
}

template <class _Elem, class _Traits, class _Alloc>
_NODISCARD inline bool operator<=(const basic_string<_Elem, _Traits, _Alloc>& _Left,
    _In_z_ const _Elem* const _Right) { // test if string <= NTCTS
    return !(_Right < _Left);
}

template <class _Elem, class _Traits, class _Alloc>
_NODISCARD inline bool operator>=(const basic_string<_Elem, _Traits, _Alloc>& _Left,
    const basic_string<_Elem, _Traits, _Alloc>& _Right) noexcept { // test if string >= string
    return !(_Left < _Right);
}

template <class _Elem, class _Traits, class _Alloc>
_NODISCARD inline bool operator>=(
    _In_z_ const _Elem* const _Left, const basic_string<_Elem, _Traits, _Alloc>& _Right) { // test if NTCTS >= string
    return !(_Left < _Right);
}

template <class _Elem, class _Traits, class _Alloc>
_NODISCARD inline bool operator>=(const basic_string<_Elem, _Traits, _Alloc>& _Left,
    _In_z_ const _Elem* const _Right) { // test if string >= NTCTS
    return !(_Left < _Right);
}

using string    = basic_string<char, char_traits<char>, allocator<char>>;
using wstring   = basic_string<wchar_t, char_traits<wchar_t>, allocator<wchar_t>>;
using u16string = basic_string<char16_t, char_traits<char16_t>, allocator<char16_t>>;
using u32string = basic_string<char32_t, char_traits<char32_t>, allocator<char32_t>>;

// STRUCT TEMPLATE SPECIALIZATION hash
template <class _Elem, class _Traits, class _Alloc>
struct hash<basic_string<_Elem, _Traits, _Alloc>> { // hash functor for basic_string
    _CXX17_DEPRECATE_ADAPTOR_TYPEDEFS typedef basic_string<_Elem, _Traits, _Alloc> argument_type;
    _CXX17_DEPRECATE_ADAPTOR_TYPEDEFS typedef size_t result_type;

    _NODISCARD size_t operator()(const basic_string<_Elem, _Traits, _Alloc>& _Keyval) const
        noexcept { // hash _Keyval to size_t value by pseudorandomizing transform
        return _Hash_array_representation(_Keyval.c_str(), _Keyval.size());
    }
};

// basic_string INSERTERS AND EXTRACTORS
template <class _Elem, class _Traits, class _Alloc>
inline basic_istream<_Elem, _Traits>& operator>>(
    basic_istream<_Elem, _Traits>&& _Istr, basic_string<_Elem, _Traits, _Alloc>& _Str) { // extract a string
    using _Myis   = basic_istream<_Elem, _Traits>;
    using _Ctype  = typename _Myis::_Ctype;
    using _Mystr  = basic_string<_Elem, _Traits, _Alloc>;
    using _Mysizt = typename _Mystr::size_type;

    typename _Myis::iostate _State = _Myis::goodbit;
    bool _Changed                  = false;
    const typename _Myis::sentry _Ok(_Istr);

    if (_Ok) { // state okay, extract characters
        const _Ctype& _Ctype_fac = _STD use_facet<_Ctype>(_Istr.getloc());
        _Str.erase();

        _TRY_IO_BEGIN
        _Mysizt _Size =
            0 < _Istr.width() && (_Mysizt) _Istr.width() < _Str.max_size() ? (_Mysizt) _Istr.width() : _Str.max_size();
        typename _Traits::int_type _Meta = _Istr.rdbuf()->sgetc();

        for (; 0 < _Size; --_Size, _Meta = _Istr.rdbuf()->snextc()) {
            if (_Traits::eq_int_type(_Traits::eof(), _Meta)) { // end of file, quit
                _State |= _Myis::eofbit;
                break;
            } else if (_Ctype_fac.is(_Ctype::space, _Traits::to_char_type(_Meta))) {
                break; // whitespace, quit
            } else { // add character to string
                _Str.push_back(_Traits::to_char_type(_Meta));
                _Changed = true;
            }
        }
        _CATCH_IO_(_Myis, _Istr)
    }

    _Istr.width(0);
    if (!_Changed) {
        _State |= _Myis::failbit;
    }

    _Istr.setstate(_State);
    return _Istr;
}

template <class _Elem, class _Traits, class _Alloc>
inline basic_istream<_Elem, _Traits>& operator>>(
    basic_istream<_Elem, _Traits>& _Istr, basic_string<_Elem, _Traits, _Alloc>& _Str) { // extract a string
    return _STD move(_Istr) >> _Str;
}

template <class _Elem, class _Traits, class _Alloc>
inline basic_ostream<_Elem, _Traits>& operator<<(
    basic_ostream<_Elem, _Traits>& _Ostr, const basic_string<_Elem, _Traits, _Alloc>& _Str) { // insert a string
    return _Insert_string(_Ostr, _Str.data(), _Str.size());
}

// basic_string LITERALS
inline namespace literals {
    inline namespace string_literals {
        _NODISCARD inline string operator"" s(
            const char* _Str, size_t _Len) { // construct literal from [_Str, _Str + _Len)
            return string(_Str, _Len);
        }

        _NODISCARD inline wstring operator"" s(
            const wchar_t* _Str, size_t _Len) { // construct literal from [_Str, _Str + _Len)
            return wstring(_Str, _Len);
        }

        _NODISCARD inline u16string operator"" s(
            const char16_t* _Str, size_t _Len) { // construct literal from [_Str, _Str + _Len)
            return u16string(_Str, _Len);
        }

        _NODISCARD inline u32string operator"" s(
            const char32_t* _Str, size_t _Len) { // construct literal from [_Str, _Str + _Len)
            return u32string(_Str, _Len);
        }
    } // namespace string_literals
} // namespace literals

#if _HAS_CXX17
namespace pmr {
    template <class _Elem, class _Traits = char_traits<_Elem>>
    using basic_string = _STD basic_string<_Elem, _Traits, polymorphic_allocator<_Elem>>;

    using string    = basic_string<char>;
    using u16string = basic_string<char16_t>;
    using u32string = basic_string<char32_t>;
    using wstring   = basic_string<wchar_t>;
} // namespace pmr
#endif // _HAS_CXX17
_STD_END

#pragma pop_macro("new")
_STL_RESTORE_CLANG_WARNINGS
#pragma warning(pop)
#pragma pack(pop)
#endif // RC_INVOKED
#endif // _XSTRING_

/*
 * Copyright (c) by P.J. Plauger. All rights reserved.
 * Consult your license regarding permissions and restrictions.
V6.50:0009 */
